using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Deployment.Application;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Media;
using System.Net;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using WowAceUpdater.Properties;
using DownloadProgressChangedEventArgs=System.Net.DownloadProgressChangedEventArgs;
using Timer=System.Threading.Timer;

namespace WowAceUpdater
{
    public partial class MainForm : Form
    {
        #region Delegates

        public delegate void IndexProgressCallback(
            ToolStripStatusLabel p, long totalBytes, long recievedBytes);

        #endregion

        #region constant

        private const int INDEX_ITEMCAT = 4;

        private const int INDEX_ITEMDESC = 1;

        private const int INDEX_ITEMNAME = 0;

        private const int INDEX_ITEMSTATUS = 5;

        #endregion

        #region field

        private static readonly string CHANGE_SUMMARY_LOG =
            Path.Combine(Application.CommonAppDataPath, "ChangeLog.html");

        private static readonly List<int> listSelection = new List<int>();
        private static readonly object oSearchLock = new Object();

        private static readonly Object oUpdateLock = new Object();

        private static readonly string UPDATE_LOG =
            Path.Combine(Application.CommonAppDataPath, "waulog.txt");


//        private static readonly string WOWACEUPDATER_LATEST_VERSION_FILE_URL =
//            "http://wowaceupdater.svn.sourceforge.net/viewvc/*checkout*/wowaceupdater/trunk/Version.txt";


        private static int _errorCount;
        private static bool _quiet; // lazy
        private static int _remainingCount;
        private static StringBuilder _sb1;

        private static StringBuilder _sb2;

        private static StringBuilder _sb3;
        private static long _totalBandwidth = 0;
        private static int _updateCount;
        private static Timer bandwidthTimer;
#pragma warning disable 219
        private static volatile int indexCachePercent = 0;
        private static volatile int indexCachePercent2 = 0;
#pragma warning restore 219
        private static long indexCacheRecievedBytes = 0;
        private static long indexCacheRecievedBytes2 = 0;
        private static long indexCacheTotalBytes = 0;
        private static long indexCacheTotalBytes2 = 0;
        private static volatile string selectedCat = null;

        private static BackgroundWorker UpdateCheckMonkey;

        private readonly SortedList<string, ListViewItem> _addonMap =
            new SortedList<string, ListViewItem>();

        private readonly List<ListViewItem> _itemCache = new List<ListViewItem>();

        private readonly ListViewColumnSorter _listViewColumnSorter =
            new ListViewColumnSorter();

        private readonly TextBoxWriter _outputWriter;

        private readonly TextInvoker _safeBandwidthLabel;

        private readonly TextInvoker _safeInterfaceVersion;
        private readonly TextInvoker _safeServerVersion;
        private readonly TextInvoker _safeStatusLabel;

        private readonly ColumnHeader _statusHeader = new ColumnHeader();
        private readonly Queue<SVNProcess> _svnProcesses = new Queue<SVNProcess>();
        private readonly List<ListViewItem> _virtualInstalled = new List<ListViewItem>();

        private readonly List<ListViewItem> _virtualUpdated = new List<ListViewItem>();

        // In case we want to use it

        private readonly Uri ADS_PAGE_URL = new Uri("http://files.wowace.com/ads.html");

        private readonly string DOWNLOAD_PAGE_URL_SF =
            "http://sourceforge.net/project/showfiles.php?group_id=178751";

        private readonly string DOWNLOAD_PAGE_URL_WOWACE =
            "http://www.wowace.com/wau/publish.htm";

        private readonly Queue<BackgroundWorker> searchQueue;

        private readonly string SOLUTIONS_THREAD =
            "http://www.wowace.com/forums/index.php?topic=8298.0";

        // Parnic - queue up search workers. this fixes a problem with typing really fast causing odd search results that don't match

        //static long sizeOfUpdate;

        private readonly Timer statusTimer;

        private string _appTitle;
        private string _appTitleBase;

        // Parnic - for searching addons
        private ListViewItem[] _fullAddonList;

        private volatile bool _isInserting = false;

        private volatile bool _isLoading = false;

        private volatile bool _isRestartRequired = false;
        private ToolStripButton _lastChecked;

        private ListViewItem[] _lastSearchResult = null;

        private DateTime _updateStartTime;
        private List<string> _virtualInstalledTmp;
        private List<string> _virtualUpdatedTmp;
        private bool bCheckedVersion = false;

        private int c2HW;

        private int c3HW;


        private bool canRetryRefresh = false;
        private bool checkedToc = false;
        private ListView currentListView = null;

        #endregion

        #region Constructors

        public MainForm()
        {
            InitializeComponent();

            viewToolStripMenuItem_DropDownOpening(null, null);

            Program.LogDbg(string.Format("Layout Save Location <{0}>",
                                         layoutSaver.GetPathOfRootFolder(false)));

#if DEBUG
            debugToolStripMenuItem.Visible = true;
#else
            debugToolStripMenuItem.Visible = false;
#endif
            if (!string.IsNullOrEmpty(Settings.Default.LastTOCValue))
                toolStripStatusLabelCurrentTOC.Text = "TOC: " + Settings.Default.LastTOCValue;


            AddCategory(categorybox, Resources.NoCategoryFilter);
            categorybox.Width = categorybox.DropDownWidth;

            _safeStatusLabel = TextInvoker.GetInvoker(_statusLabel);
            _safeBandwidthLabel = TextInvoker.GetInvoker(toolStripBandwidthUsed);
            _safeServerVersion = TextInvoker.GetInvoker(toolStripStatusLabelVersion);
            _safeInterfaceVersion = TextInvoker.GetInvoker(toolStripStatusLabelCurrentTOC);

            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);

            TimerCallback timerDelegate = timerStatus_Tick;

            AddBandwidthUsed(Settings.Default.BandwidthUsed);

            TimerCallback timerBandwidthDelegate = bandwidthTimer_Tick;
            bandwidthTimer = new Timer(timerBandwidthDelegate, null, 5000, 3000);
            statusTimer = new Timer(timerDelegate, null, 10000, 30000);


            _outputWriter = new TextBoxWriter(_outputTextBox);

            _addonListView.ListViewItemSorter = _listViewColumnSorter;
            _statusHeader.Text = "Status";

            // Parnic - queue up search workers. this fixes a problem with typing really fast causing odd search results that don't match
            searchQueue = new Queue<BackgroundWorker>(1);

            if (Program.bRefresh)
            {
                WowAceFilesServer.CacheDirty = true;
            }
        }

        #endregion

        #region Properties

        private string ApplicationTitle
        {
            //get { return _appTitle; }
            set
            {
                _appTitle = value;
                if (_appTitle.Length > 0)
                {
                    Text = string.Format(Resources.String0Dash1, _appTitleBase, _appTitle);
                }
                else
                {
                    Text = _appTitleBase;
                }
            }
        }

        internal string VersionText
        {
            get { return _safeServerVersion.Text; }
            set { _safeServerVersion.Text = string.Format(Resources.ServerVersion0, value); }
        }

        internal string BandwidthText
        {
            get { return _safeBandwidthLabel.Text; }
            set { _safeBandwidthLabel.Text = value; }
        }

        private static string IdleStatusText
        {
            get
            {
                string age;
                TimeSpan t = WowAceFilesServer.CacheAge;

                if (t == TimeSpan.MaxValue)
                {
                    age = Resources.NotCached;
                }
                else if (t.Days > 0)
                {
                    age = Resources.Day;
                }
                else if (t.Hours > 0)
                {
                    age = string.Format(Resources.Hours, t.Hours);
                }
                else if (t.Minutes > WowAceFilesServer.CACHE_MIN_MINUTES)
                {
                    age = string.Format(Resources.Min, t.Minutes);
                }
                else
                {
                    age =
                        string.Format(Resources.Under1Min,
                                      WowAceFilesServer.CACHE_MIN_MINUTES);
                }

                return string.Format(Resources.ReadyDataIs0Old, age);
            }
        }

        public bool IsRestartRequired
        {
            get { return _isRestartRequired; }
            set
            {
                if (!_isRestartRequired && value)
                {
                    notifyUpdate.Icon = Icon;
                    notifyUpdate.BalloonTipTitle = Resources.ApplicationUpdated;
                    notifyUpdate.BalloonTipText = Resources.WowAceUpdaterHasBeenUpdated;
                    notifyUpdate.Visible = true;
                    notifyUpdate.Text = Resources.WowAceUpdaterUpdated;

                    notifyUpdate.ShowBalloonTip(5000);
                }
                _isRestartRequired = value;
            }
        }

        private string StatusText
        {
            //get { return _safeStatusLabel.Text; }

            set { _safeStatusLabel.Text = value; }
        }

        public static long TotalBandwidth
        {
            get { return Interlocked.Read(ref _totalBandwidth); }
        }

        public static Timer BandwidthTimer
        {
            get { return bandwidthTimer; }
        }

        #endregion

        internal void CheckForUpdates()
        {
            if (IsDisposed)
                return;

            if (InvokeRequired)
                BeginInvoke(new CheckForUpdatesFunction(CheckForUpdates));
            else
            {
                Program.LogDbg("Update Check");
                ApplicationDeployment.CurrentDeployment.CheckForUpdateAsync();
            }
        }

        internal void DoUpdate()
        {
            if (IsDisposed)
                return;

            if (InvokeRequired)
                BeginInvoke(new DoUpdateFunction(DoUpdate));
            else
            {
                Program.LogDbg("Update");
                ApplicationDeployment.CurrentDeployment.UpdateAsync();
            }
        }

        //[SecurityPermission(SecurityAction.Assert, Unrestricted = true)]

        private void _addonListView_ItemSelectionChanged(
            object sender, ListViewItemSelectionChangedEventArgs e)
        {
            Debug.WriteLine(string.Format("IS {0}:{1}", e.ItemIndex, e.IsSelected));

            if (e.IsSelected)
            {
                if (!listSelection.Contains(e.ItemIndex))
                {
                    listSelection.Add(e.ItemIndex);
                }
            }
            else
            {
                if (listSelection.Contains(e.ItemIndex))
                {
                    listSelection.Remove(e.ItemIndex);
                }
            }
        }

        private void _addonListView_VirtualItemsSelectionRangeChanged(
            object sender, ListViewVirtualItemsSelectionRangeChangedEventArgs e)
        {
            Debug.WriteLine(
                string.Format("VIS {0}-{1}:{2}", e.StartIndex, e.EndIndex, e.IsSelected));

            for (int i = e.StartIndex; i <= e.EndIndex; i++)
            {
                if (e.IsSelected)
                {
                    if (!listSelection.Contains(i))
                    {
                        listSelection.Add(i);
                    }
                }
                else
                {
                    if (listSelection.Contains(i))
                    {
                        listSelection.Remove(i);
                    }
                }
            }
        }

        private void openLocalUserDirToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShellOpenURL(FileSystem.TempDirectory);
        }

        private void openCommonDataDiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShellOpenURL(Application.CommonAppDataPath);
        }

        private void readLogFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Program.FlushLog();

            //GZipInputStream gzi = new GZipInputStream(
            //    File.OpenRead(Program.DIAGNOSTIC_LOG.FullName));

            LoadTextFileInOutputWindow(Program.DIAGNOSTIC_LOG.FullName);
        }

        private void LoadTextFileInOutputWindow(string file)
        {
            _outputTextBox.Clear();

            _outputTextBox.LoadFile(file, RichTextBoxStreamType.PlainText);

            toolButtonOutput.PerformClick();
        }

        private void MainForm_Layout(object sender, LayoutEventArgs e)
        {
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            ShellOpenURL(Application.LocalUserAppDataPath);
        }

        private void toolButtonPanel_Click(object sender, EventArgs e)
        {
            ToolStripButton b = sender as ToolStripButton;

            if (b != null && b.Enabled)
            {
                foreach (ToolStripItem i in b.GetCurrentParent().Items)
                {
                    ToolStripButton b2 = i as ToolStripButton;
                    if (b2 == null || b2 == b || !b2.Checked)
                    {
                        continue;
                    }

                    b2.Checked = false;
                }

                Panel p =
                    toolStripContainer2.ContentPanel.Controls[(string) b.Tag] as Panel;

                if (p != null)
                {
                    p.BringToFront();
                    b.Checked = true;
                    _lastChecked = !_isInserting ? b : _lastChecked;


                    if (p == panelOutput)
                    {
                        _outputTextBox.Parent = panelOutput;
                        _outputTextBox.Dock = DockStyle.Fill;

                        currentListView = null;
                    }
                    else if (p == panelUpdated)
                    {
                        _outputTextBox.Parent = splitContainer2.Panel2;
                        _outputTextBox.Dock = DockStyle.Fill;

                        currentListView = _addonListView2;
                    }
                    else if (p == panelAll)
                    {
                        currentListView = _addonListView;
                    }
                    else if (p == panelInstalled)
                    {
                        currentListView = _addonListView3;
                    }
                    listSelection.Clear();
                    _addonListView.SelectedItems.Clear();

                    // if (p.Contains(_addonListView))
                    // {

                    if (_fullAddonList != null && currentListView != null)
                    {
                        if (currentListView.VirtualMode)
                        {
                            RebuildVirtualLists(ref _lastSearchResult);
                        }
                        else
                        {
                            RebuildList(ref _lastSearchResult);
                        }
                    }


                    // }
                    // else
                    //{
                    //    if (_fullAddonList != null)
                    //          RebuildVirtualLists(_fullAddonList);

                    //    }
                }
            }
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            Settings.Default.BandwidthUsed = TotalBandwidth;
            Settings.Default.Save();
        }

        private void menuOutputDuringUpdate_CheckedChanged(object sender, EventArgs e)
        {
            Settings.Default.DisplayOutputDuringUpdate = menuOutputDuringUpdate.Checked;
            Settings.Default.Save();
        }

        private void toolStripSplitButton1_ButtonClick(object sender, EventArgs e)
        {
            txtSearch.Text = String.Empty;
            categorybox.SelectedIndex = 0;
        }

        private void toolStrip_ParentChanged(object sender, EventArgs e)
        {
            ToolStrip ts = sender as ToolStrip;

            if (ts != null)
            {
                if (ts.Parent != null)
                {
                    if (ts.Parent.Dock == DockStyle.Left)
                    {
                        ts.TextDirection = ToolStripTextDirection.Vertical270;
                    }

                    else if (ts.Parent.Dock == DockStyle.Right)
                    {
                        ts.TextDirection = ToolStripTextDirection.Vertical90;
                    }

                    else if (ts.Parent.Dock == DockStyle.Top ||
                             ts.Parent.Dock == DockStyle.Bottom)
                    {
                        ts.TextDirection = ToolStripTextDirection.Horizontal;
                    }

                    foreach (ToolStripItem i in ts.Items)
                        i.TextDirection = ts.TextDirection;
                }
            }
        }

        private void _addonListView3_SelectedIndexChanged(object sender, EventArgs e)
        {
        }

        //private void toolButton_CheckedChanged(object sender, EventArgs e)
        //{
        //    ToolStripButton b = sender as ToolStripButton;

        //    if (b == null)
        //    {
        //        return;
        //    }

        //    b.BackColor = b.Checked ? SystemColors.Control : SystemColors.ActiveCaption;
        //}

        private void _aboutMenuItem_Click(object sender, EventArgs e)
        {
            new AboutForm().ShowDialog(this);
        }

        private void _addonListView_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (_isInserting)
            {
                return;
            }

            if (_addonListView.ShowGroups)
                _addonListView.ShowGroups = false;

            // Determine if the clicked column is already the column that is 
            // being sorted.
            if (e.Column == _listViewColumnSorter.SortColumn)
            {
                // Reverse the current sort direction for this column.
                if (_listViewColumnSorter.Order == SortOrder.Ascending)
                {
                    _listViewColumnSorter.Order = SortOrder.Descending;
                }
                else
                {
                    _listViewColumnSorter.Order = SortOrder.Ascending;
                }
            }
            else
            {
                // Set the column number that is to be sorted; default to ascending.
                _listViewColumnSorter.SortColumn = e.Column;
                _listViewColumnSorter.Order = SortOrder.Ascending;
            }

            // Perform the sort with these new sort options.
            SortListViewItems();
        }

        private void _addonListView_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            ListView lv = sender as ListView;
            if (lv != null)
            {
                if (lv.VirtualMode)
                {
                    ListViewItem i = e.Item.Tag as ListViewItem;

                    if (i != null)
                    {
                        bool newState = (i.Checked == e.Item.Checked)
                                            ? !i.Checked
                                            : i.Checked;

                        i.Checked = newState;

                        foreach (ListViewItem lvi in GetSelectedAddons())
                        {
                            if (lvi.Text != e.Item.Text)
                            {
                                ((ListViewItem) lvi.Tag).Checked = newState;
                                lv.RedrawItems(lvi.Index, lvi.Index, false);
                            }
                        }
                    }
                }
            }
            if (!_isInserting)
            {
                UpdateCheckedItemStatusLabel();
            }
        }


        private void _addonListView3_RetrieveVirtualItem(
            object sender, RetrieveVirtualItemEventArgs e)
        {
            ListViewItem i = _virtualInstalled[e.ItemIndex];

            e.Item = i.Clone() as ListViewItem;
            e.Item.Tag = i;
            lock (_itemCache)
                if (!_itemCache.Contains(e.Item))
                {
                    _itemCache.Add(e.Item);
                }
        }

        private void _addonListView2_RetrieveVirtualItem(
            object sender, RetrieveVirtualItemEventArgs e)
        {
            ListViewItem i = _virtualUpdated[e.ItemIndex];


            e.Item = i.Clone() as ListViewItem;
            e.Item.Tag = i;
            lock (_itemCache)
                if (!_itemCache.Contains(e.Item))
                {
                    _itemCache.Add(e.Item);
                }
        }

        private void _editMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            autoSelectAddonsToolStripMenuItem.Enabled =
                Directory.Exists(WowEnvironment.AddonsDirectory);
            reloadIndexToolStripMenuItem.Enabled = !_isLoading;
        }

        private void _exitMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void _fileMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            bool canupdate = Directory.Exists(Settings.Default.WowInstallDirectory);
            bool marked = GetCheckedItems().Count > 0;

            canupdate = canupdate && !_isInserting;

            withExternalsToolStripMenuItem.Enabled = canupdate && marked;
            withoutExternalsToolStripMenuItem.Enabled = canupdate && marked;
            uninstallMarkedAddonsToolStripMenuItem.Enabled = canupdate && marked;
            updateAllInstalledAddonsToolStripMenuItem.Enabled = canupdate;
            toolStripMenuReinstall.Enabled = canupdate;
            reinstallMarkedAddons.Enabled = canupdate && marked;

            autoExternalsToolStripMenuItem.Enabled = canupdate && marked;

            loadAddonSnapshot.Enabled = canupdate && WowEnvironment.LastBackupFile.Exists;
        }

        private void _outputTextBox_LinkClicked(object sender, LinkClickedEventArgs e)
        {
            ShellOpenURL(e.LinkText);
        }

        private void _preferencesMenuItem_Click(object sender, EventArgs e)
        {
            string wowPath = Settings.Default.WowInstallDirectory;
            new SettingsForm().ShowDialog(this);
            DefaultsConfiguration();
            if (wowPath != Settings.Default.WowInstallDirectory)
            {
                RefreshList();
            }
        }

        private void _statusLabel_TextChanged(object sender, EventArgs e)
        {
            statusTimer.Change(10000, 60000);
        }

        private void autoExternalsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            InstallUpdateCheckedAddons(ExternalMode.AUTO);
        }

        private void autoSelectAddonsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FlagInstalledAddons();
            // 			foreach (ListViewItem item in _addonListView.Groups["Installed"].Items)
            // 			{
            // 				item.Checked = true;
            // 			}
        }



        private void SvnOutputHandler(object sendingProcess,
                                      DataReceivedEventArgs outLine)
        {
            SVNProcess p = sendingProcess as SVNProcess;

            // Collect the sort command output.
            if (!String.IsNullOrEmpty(outLine.Data) && p != null)
            {
                _outputWriter.WriteLine(string.Format("{0}: {1}",
                                                      p.Addon, outLine.Data));
                Program.LogDbg(string.Format("SVN - {0}: {1}",
                                             p.Addon, outLine.Data));
            }
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            Object oLock = oUpdateLock;

            /*			_outputWriter.Clear();*/
            BackgroundWorkerParams args = e.Argument as BackgroundWorkerParams;

            if (args == null)
            {
                _outputWriter.WriteLine(Resources.InvalidWorkerParams);
                return;
            }
            LinkedList<string> addonsToProcess = new LinkedList<string>(args.AddonNames);
            LinkedList<string> addonsProcessed = new LinkedList<string>();
            LinkedList<string> addonsProcessing = new LinkedList<string>();

            _sb1 = new StringBuilder();
            _sb2 = new StringBuilder();
            _sb3 = new StringBuilder();

            _outputWriter.WriteLine(Resources.UpdatingFrom + Settings.Default.AceFilesPath);

            if (WowAceFilesServer.CacheAge != TimeSpan.MaxValue)
            {
                _outputWriter.WriteLine(Resources.CacheAge,
                                        WowAceFilesServer.CacheAge.TotalMinutes,
                                        WowAceFilesServer.CACHE_MIN_MINUTES);
            }

            // If our cache was dirty, update it now, so that when we finish the update process
            // the file list will be correct.
            if (WowAceFilesServer.CacheDirty)
            {
                using (
                    new TextWriterMessageWrapper(Resources.UpdatingCachedFileIndex,
                                                 _outputWriter))
                    WowAceFilesServer.UpdateIndexFile();
            }

            BackgroundWorker self = sender as BackgroundWorker;

            ChangeLog.ClearAddons();
            while (addonsToProcess.Count > 0 && e.Cancel != true)
            {
                float progress_percent;
                string addon;
                bool processed;
                lock (oLock)
                {
                    progress_percent = addonsProcessed.Count/
                                       (float)
                                       (addonsToProcess.Count + addonsProcessed.Count);
                    addon = addonsToProcess.First.Value;

                    _remainingCount = addonsToProcess.Count;

                    addonsProcessing.AddLast(addon);
                    addonsToProcess.RemoveFirst();
                    processed = addonsProcessed.Contains(addon);
                }

                if (self != null)
                {
                    self.ReportProgress((int) Math.Floor((progress_percent*100)));
                }

                if (!processed)
                {
                    if (FileSystem.IsDirectoryProtected(
                        WowEnvironment.GetAddonDirectory(addon)))
                    {
                        _outputWriter.WriteLine(
                            String.Format(Resources.SkippingProtected, addon));
                    }
                    else
                    {
                        string addondir = WowEnvironment.GetAddonDirectory(addon);
                        if (FileSystem.IsWorkingCopy(addondir))
                        {
                            ProcessStartInfo psi = null;
                            if (FileSystem.IsSvnWorkingCopy(addondir))
                            {
                                VersionNumber ver = WowEnvironment.GetAddonRevision(addon);

                                string without = "--ignore-externals";
                                string with = "";
                                string unknown = Settings.Default.DefaultUpdateModeWithExternals ? with : without;
                                string mode = "";
                                switch (ver.Externals)
                                {
                                    case VersionNumber.ExternalsType.WITH:
                                        mode = with;
                                        break;
                                    case VersionNumber.ExternalsType.WITHOUT:
                                        mode = without;
                                        break;
                                    case VersionNumber.ExternalsType.UNKNOWN:
                                        mode = unknown;
                                        break;
                                }

                                psi = new ProcessStartInfo("svn.exe",
                                                           string.Format("update \"{0}\" {1}",
                                                                         addondir,mode));
                            }
                            else if (FileSystem.IsGitWorkingCopy(addondir))
                            {
                                psi = new ProcessStartInfo("git.exe",
                                                           string.Format("pull \"{0}\"", addondir));
                                
                            }

                            if (psi != null)
                            {
                                psi.UseShellExecute = false;

                                psi.CreateNoWindow = true;

                                // Redirect the standard output of the sort command.  
                                // This stream is read asynchronously using an event handler.
                                psi.RedirectStandardOutput = true;
                                psi.RedirectStandardError = true;

                                SVNProcess p = new SVNProcess();

                                // Set our event handler to asynchronously read the sort output.
                                p.OutputDataReceived += SvnOutputHandler;
                                p.ErrorDataReceived += SvnOutputHandler;
                                p.StartInfo = psi;
                                p.Addon = addon;
                                p.Start();


                                p.BeginOutputReadLine();
                                p.BeginErrorReadLine();

                                _svnProcesses.Enqueue(p);
                            }
                        }
                        else
                        {
                            DAndEArgs d =
                                new DAndEArgs(addon,
                                              args.SkipExternals,
                                              args.SkipVersionCheck,
                                              args.DeleteBeforeExtract,
                                              addonsToProcess,
                                              addonsProcessed,
                                              addonsProcessing,
                                              oLock);

                            while (true)
                            {
                                if (!backgroundWorker2.IsBusy)
                                {
                                    d.outputWriter = new StringWriter(_sb1);
                                    backgroundWorker2.RunWorkerAsync(d);
                                    break;
                                }

                                if (!backgroundWorker3.IsBusy)
                                {
                                    d.outputWriter = new StringWriter(_sb2);
                                    backgroundWorker3.RunWorkerAsync(d);
                                    break;
                                }

                                if (!backgroundWorker4.IsBusy)
                                {
                                    d.outputWriter = new StringWriter(_sb3);
                                    backgroundWorker4.RunWorkerAsync(d);
                                    break;
                                }

                                Thread.Sleep(10);
                            }
                        }
                    }
                }
                else
                {
                    Program.LogDbg("Skipping " + addon);
                }

                Program.LogDbg("Addons Left " + addonsToProcess.Count);

                while (addonsToProcess.Count == 0 &&
                       (backgroundWorker2.IsBusy || backgroundWorker3.IsBusy ||
                        backgroundWorker4.IsBusy))
                {
                    Thread.Sleep(100);
                }

                while (_svnProcesses.Count > 0)
                {
                    SVNProcess p = _svnProcesses.Dequeue();

                    p.WaitForExit();
                }
            }
        }

        private void backgroundWorker1_ProgressChanged(
            object sender, ProgressChangedEventArgs e)
        {
            if (toolProgressBar.Visible == false)
            {
                toolProgressBar.Visible = true;
            }

            toolProgressBar.Value = e.ProgressPercentage;

            StatusText = string.Format(Resources.UpdatingRemaining, _remainingCount);
        }

        private void backgroundWorker1_RunWorkerCompleted(
            object sender, RunWorkerCompletedEventArgs e)
        {
            toolProgressBar.Visible = false;
            toolStripMenuCancelUpdate.Visible = false;

            while (backgroundWorker2.IsBusy)
            {
                Thread.Sleep(250);
            }

            if (_updateCount > 0)
            {
                _outputWriter.WriteLine("Creating Change Summary");
                StringBuilder sb = ChangeLog.CreateChangeLog();

                webView.AllowNavigation = true;
                webView.DocumentText = sb.ToString();

                File.WriteAllText(CHANGE_SUMMARY_LOG, sb.ToString());
            }

            TimeSpan delta = DateTime.Now - _updateStartTime;

            FileInfo fi = new FileInfo(UPDATE_LOG);
            StreamWriter sw = File.CreateText(fi.ToString());
            using (sw)
            {
                _outputTextBox.SaveFile(sw.BaseStream, RichTextBoxStreamType.PlainText);

                sw.WriteLine();
                sw.WriteLine("*** Thread 2 ****");
                sw.WriteLine(_sb1.ToString());
                sw.WriteLine();
                sw.WriteLine("*** Thread 3 ****");
                sw.WriteLine(_sb2.ToString());

                sw.WriteLine();
                sw.WriteLine("*** Thread 4 ****");
                sw.WriteLine(_sb3.ToString());

                sw.WriteLine("Update Complete ({0}, total seconds: {1:F2})",
                             DateTime.Now,
                             delta.TotalSeconds);

                sw.WriteLine();


                Program.FlushLog();
            }

            _outputWriter.WriteLine(Resources.SavingLogTo);
            _outputWriter.WriteLine(Resources.UpdateCompleteTotalSeconds,
                                    DateTime.Now,
                                    delta.TotalSeconds);
            _outputWriter.WriteLine(Resources.SummaryUpdatedErrors,
                                    _updateCount,
                                    _errorCount);

            _outputWriter.WriteLine(" ");
            _outputWriter.WriteLineColored(Color.Blue,
                                           Resources.YouCanAccessTheLogsFromTheViewMenu);
            _outputWriter.WriteLine(" ");

            if (e.Cancelled)
            {
                _outputWriter.WriteLineColored(Color.Red, Resources.UpdateCanceled);
            }
            else
            {
                _outputWriter.WriteLine(Resources.UpdateComplete);
            }

            ResetListViewGroups();
            EnableUserInteraction(true);
            Application.DoEvents();

            if (Program.bAutoExit)
            {
                Close();
            }
        }

        private void backgroundWorkerDownloadAndExtract(object sender, DoWorkEventArgs e)
        {
            DAndEArgs d = e.Argument as DAndEArgs;

            if (d != null)
            {
                DownloadAndExtract(d.addonName,
                                   d.skipExternals,
                                   d.skipVersionCheck,
                                   d.deleteBeforeExtract,
                                   d.list,
                                   d.listDone,
                                   d.listCurrent,
                                   d.outputWriter,
                                   d.oLock);
            }
        }

        private void bandwidthTimer_Tick(object sender)
        {
            BandwidthText = FormatBandwidth(TotalBandwidth);
        }

        private void categorybox_SelectedIndexChanged(object sender, EventArgs e)
        {
            //combobox select category
            txtSearch_TextChanged(sender, e);
        }

        private void chkSearchDescs_CheckedChanged(object sender, EventArgs e)
        {
            txtSearch_TextChanged(sender, e);
        }

        // Parnic - when the user checks to only search names or descriptions, make sure we update the searched results immediately
        private void chkSearchNames_CheckedChanged(object sender, EventArgs e)
        {
            txtSearch_TextChanged(sender, e);
        }

        private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
        {
            ContextMenuStrip cms = sender as ContextMenuStrip;
            ListView listView = null;

            if (cms != null)
            {
                listView = cms.SourceControl as ListView;
            }

            if (listView != null)
            {
                IList<int> indexes = GetSelectedIndexes(listView);

                if (indexes != null)
                {
                    if (indexes.Count == 1)
                    {
                        ListViewItem item = listView.Items[indexes[0]];
                        openAddonFolderToolStripMenuItem.Enabled =
                            Directory.Exists(WowEnvironment.GetAddonDirectory(item.Text));
                        viewChangelogToolStripMenuItem.Enabled = true;
                        rssAddonItem addonSource =
                            WowAceFilesServer.FilesLookup[item.Text];

                        if (WowAceFilesServer.GetLink(addonSource) != null)
                        {
                            openAddonsWikiToolStripMenuItem.Enabled = true;
                        }
                        else
                        {
                            openAddonsWikiToolStripMenuItem.Enabled = false;
                        }

                        if (WowAceFilesServer.GetComments(addonSource) != null)
                        {
                            toolStripOpenForumThread.Enabled = true;
                        }
                        else
                        {
                            toolStripOpenForumThread.Enabled = false;
                        }

                        if ((item.SubItems[INDEX_ITEMSTATUS].Text == "SVN" &&
                             Settings.Default.SkipSvnWorkingCopies) ||
                            item.SubItems[INDEX_ITEMSTATUS].Text == "Ignored")
                        {
                            toolStripMenuUninstallCurrent.Enabled = false;
                            toolStripMenuInstallCurrent.Enabled = false;
                        }
                        else
                        {
                            toolStripMenuInstallCurrent.Enabled = true;

                            if (item.SubItems[INDEX_ITEMSTATUS].Text == "Not Installed")
                            {
                                toolStripMenuUninstallCurrent.Enabled = false;
                                toolStripMenuInstallCurrent.Text = Resources.Install +
                                                                   item.Text;
                            }
                            else if (item.SubItems[INDEX_ITEMSTATUS].Text == "SVN")
                            {
                                toolStripMenuInstallCurrent.Text = Resources.Update +
                                                                   item.Text;
                            }
                            else
                            {
                                toolStripMenuUninstallCurrent.Enabled = true;
                                toolStripMenuInstallCurrent.Text = Resources.Update +
                                                                   item.Text;
                            }
                        }

                        toolStripMenuUninstallCurrent.Text = Resources.Uninstall +
                                                             item.Text;
                        toolStripMenuItemReinstallMarked.Text = Resources.Reinstall +
                                                                item.Text;
                        toolStripMenuItemReinstallMarked.Enabled =
                            toolStripMenuUninstallCurrent.Enabled;

                        ignoreToolStripMenuItem.Enabled = true;
                        if (Settings.Default.IgnoredAddons.Contains(item.Name))
                        {
                            ignoreToolStripMenuItem.Text = Resources.StopIgnoring +
                                                           item.Text;
                        }
                        else
                        {
                            ignoreToolStripMenuItem.Text = Resources.Ignore + item.Text;
                        }
                    }


                    else
                    {
                        bool? ignore = null;
                        bool disableIgnore = false;
                        foreach (int idx in indexes)
                            if (Settings.Default.IgnoredAddons.Contains(listView.Items[idx].Text))
                            {
                                if (ignore != false)
                                    ignore = true;
                                else
                                    disableIgnore = true;
                            }
                            else
                            {
                                if (ignore != true)
                                    ignore = false;
                                else
                                    disableIgnore = true;
                            }

                        if (!disableIgnore)
                            if (ignore != null && (bool) ignore)
                            {
                                ignoreToolStripMenuItem.Text = Resources.StopIgnoring + Resources.Selected;
                            }
                            else
                            {
                                ignoreToolStripMenuItem.Text = Resources.Ignore + Resources.Selected;
                            }

                        toolStripMenuInstallCurrent.Text = Resources.UpdateInstallSelected;
                        toolStripMenuItemReinstallMarked.Text =
                            Resources.ReinstallSelected;
                        toolStripMenuUninstallCurrent.Text = Resources.UninstallSelected;
                        ignoreToolStripMenuItem.Enabled = !disableIgnore;
                        openAddonFolderToolStripMenuItem.Enabled = false;
                        viewChangelogToolStripMenuItem.Enabled = false;
                        openAddonsWikiToolStripMenuItem.Enabled = false;
                        toolStripOpenForumThread.Enabled = false;
                    }
                }
            }
        }

        private static void CurrentDeployment_CheckForUpdateCompleted(
            object sender, CheckForUpdateCompletedEventArgs e)
        {
            Program.LogDbg("Update Check Completed");

            MainForm f = ActiveForm as MainForm;

            if (f != null)
            {
                if (e.UpdateAvailable)
                {
                    f.VersionText = "Updating...";
                    f.DoUpdate();
                }
                else
                {
                    f.VersionText = ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString(4);
                }
            }
        }

        private static void CurrentDeployment_UpdateCompleted(
            object sender, AsyncCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                Program.LogDbg(e.Error.ToString());
            }
            else if (e.Cancelled)
            {
                Program.LogDbg("Update Canceled");
            }
            else
            {
                Program.LogDbg("Update Completed");

                MainForm f = ActiveForm as MainForm;
                if (f != null)
                {
                    f.VersionText = string.Format("Updated {0}",
                                                  ApplicationDeployment.CurrentDeployment.UpdatedVersion.ToString(4));


                    f.IsRestartRequired = true;
                }
            }
        }

        private void goToDownloadPageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (ApplicationDeployment.IsNetworkDeployed)
            {
                ShellOpenURL(DOWNLOAD_PAGE_URL_WOWACE);
            }
            else
            {
                ShellOpenURL(DOWNLOAD_PAGE_URL_SF);
            }
        }

        private void ignoreToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (ListViewItem i in GetSelectedAddons())
            {
                if (Settings.Default.IgnoredAddons.Contains(i.Text))
                {
                    Settings.Default.IgnoredAddons.Remove(i.Text);
                    SetListViewGroup(i, i.SubItems["Status"], i.Name, false);
                }
                else
                {
                    Settings.Default.IgnoredAddons.Add(i.Text);
                    i.SubItems["Status"].Text = "Ignored";
                }
            }

            Settings.Default.Save();
            RefreshList(true);
        }

        private void MainForm_Activated(object sender, EventArgs e)
        {
            if (webBrowser1.Focused)
            {
                _addonListView.Focus();
            }
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            if (Settings.Default["DefaultUpdateModeWithExternals"] == null)
            {
                DialogResult rc = MessageBox.Show(this,
                                                  "The current update mode is not set.\r\n\r\nDo you update with externals? If you do not know, choose YES",
                                                  "Update Mode Not Set",
                                                  MessageBoxButtons.YesNo,
                                                  MessageBoxIcon.Question);

                if (rc == DialogResult.Yes)
                {
                    Settings.Default.DefaultUpdateModeWithExternals = true;
                    Settings.Default.AutoDeps = false;
                    Settings.Default.UnpackAddons = false;
                }
                else
                {
                    Settings.Default.DefaultUpdateModeWithExternals = false;
                    Settings.Default.AutoDeps = true;
                    Settings.Default.UnpackAddons = true;
                }

                Settings.Default.Save();
            }


            Font = SystemFonts.IconTitleFont;

            if (Text != null)
            {
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    _appTitleBase =
                        string.Format("{0} net-{1}",
                                      Text,
                                      ApplicationDeployment.CurrentDeployment.CurrentVersion.
                                          ToString(4));
                }
                else
                {
                    _appTitleBase =
                        string.Format("{0} {1}",
                                      Text,
                                      Assembly.GetExecutingAssembly().GetName().Version.
                                          ToString(4));
                }
            }
            Text = _appTitleBase;

            File.Delete(CHANGE_SUMMARY_LOG);

            DefaultsConfiguration();

            _lastChecked = toolButtonAll;

            if (Settings.Default.DisplayBackupWarningAtStartup && !Program.bNoPrompts)
            {
                DialogResult rc = MessageBox.Show(this,
                                                  Resources.
                                                      YouShouldBackUpYourAddonsDirectoryBeforeProceeding,
                                                  Resources.Warning,
                                                  MessageBoxButtons.OKCancel,
                                                  MessageBoxIcon.Warning);

                if (rc == DialogResult.OK)
                {
                    Settings.Default.DisplayBackupWarningAtStartup = false;
                    Settings.Default.Save();
                }
                else
                {
                    Close();
                }
            }

            if (!WowEnvironment.WowDirectoryExists())
            {
                _outputWriter.WriteLine(Resources.WARNINGYouWillNotBeAbleToUpdateUntil);
            }

            if (!bCheckedVersion)
            {
                DoVersionCheck();
            }

            RefreshList();

            InitMonkey();
        }

        private void MainForm_SizeChanged(object sender, EventArgs e)
        {
            ResizeListViewColumns();
        }

        private void mirrorsToolStripMenuItem_Opening(object sender, EventArgs e)
        {
            WowAceFilesServer.GetMirrors();
            // too much time to figure out a nice way windows forms blow
            ToolStripMenuItem[] mi =
                new ToolStripMenuItem[]
                    {
                        mIRROR1ToolStripMenuItem, mIRROR2ToolStripMenuItem,
                        mIRROR3ToolStripMenuItem, mIRROR4ToolStripMenuItem,
                    };

            int i = mi.GetLowerBound(0);
            foreach (string name in WowAceFilesServer.MirrorList)
            {
                if (i <= mi.GetUpperBound(0))
                    //  if (!name.Equals(WowAceFilesServer.FILES_SERVER_DEFAULT))
                {
                    mi[i].Visible = true;
                    mi[i].Text = name;
                    mi[i].Click += mirrorToolStripMenuItem_Click;
                    i++;
                }
            }

            while (i <= mi.GetUpperBound(0))
            {
                mi[i].Visible = false;
                i++;
            }

            foreach (ToolStripMenuItem ti in mi)
            {
                string s = ti.Text;
                if (s.Length == 0)
                {
                    ti.Visible = false; // hello mr. kludge
                }
                ti.Checked = ti.Text.Equals(Settings.Default.AceFilesPath);
            }
        }

        private static void mirrorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string mirror = sender.ToString();
            Settings.Default.AceFilesPath = mirror;
            Settings.Default.Save();
        }

        private void notifyUpdate_BalloonTipClicked(object sender, EventArgs e)
        {
            if (IsRestartRequired && !_isInserting)
            {
                Application.Restart();
            }
        }

        private void notifyUpdate_BalloonTipClosed(object sender, EventArgs e)
        {
        }

        private void notifyUpdate_BalloonTipShown(object sender, EventArgs e)
        {
            SystemSounds.Asterisk.Play();
        }

        private void notifyUpdate_Click(object sender, EventArgs e)
        {
            notifyUpdate.ShowBalloonTip(5000);
        }

        private void notifyUpdate_DoubleClick(object sender, EventArgs e)
        {
            Activate();
        }

        private void openAddonFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ListViewItem item = GetSelectedAddons()[0];
            Process.Start(WowEnvironment.GetAddonDirectory(item.Text));
        }

        private void openAddonsWikiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string addon_name = GetSelectedAddons()[0].Text;
            string url =
                WowAceFilesServer.GetLink(WowAceFilesServer.FilesLookup[addon_name]);

            if (url != null)
            {
                ShellOpenURL(url);
            }
        }

        private void systemToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripManager.RenderMode = ToolStripManagerRenderMode.System;
        }

        // Called by mutiple threads
        private void timerStatus_Tick(object sender)
        {
            if (!_isInserting)
            {
                StatusText = IdleStatusText;


                if (UpdateCheckMonkey != null)
                {
                    MonkeySee();
                }
            }
        }

        private void toolStripMenuCancelUpdate_Click(object sender, EventArgs e)
        {
            backgroundWorker1.CancelAsync();
        }

        private void toolStripMenuInstallCurrent_Click(object sender, EventArgs e)
        {
            InstallUpdateAddons(GetSelectedItems(), ExternalMode.AUTO);
        }

        private void toolStripMenuItemOpenAppDir_Click(object sender, EventArgs e)
        {
            Process.Start(Application.CommonAppDataPath);
        }

        private void toolStripMenuItemReinstallMarked_Click(object sender, EventArgs e)
        {
            InstallUpdateCheckedAddons(ExternalMode.AUTO, true, true);
        }

        private void toolStripMenuItemSVCleanup_Click(object sender, EventArgs e)
        {
            DialogResult rc =
                MessageBox.Show(Resources.ThisWillRemoveWoWSavedVariable,
                                Resources.Confirm,
                                MessageBoxButtons.YesNo,
                                MessageBoxIcon.Warning,
                                MessageBoxDefaultButton.Button1);

            if (rc == DialogResult.Yes)
            {
                try
                {
                    toolButtonOutput.PerformClick();

                    FileInfo backup;
                    using (
                        new TextWriterMessageWrapper("Creating SV Backup...",
                                                     _outputWriter))
                    {
                        Application.DoEvents();
                        backup = WowEnvironment.BackupSavedVariables(_outputWriter);
                    }
                    _outputWriter.WriteLineColored(Color.DarkCyan, "SV Cleanup Started:");
                    WowEnvironment.CleanSavedVariables(_outputWriter);
                    if (backup != null)
                    {
                        _outputWriter.Write("\r\n\tThe backup at: ");
                        _outputWriter.WriteColored(Color.DarkCyan, backup.FullName);
                        _outputWriter.WriteLine(
                            string.Format(
                                "\r\n\twill be overwritten next time cleanup is run\r\n\tIf you want to keep it you should copy it to another location."));
                    }
                    _outputWriter.WriteLineColored(Color.DarkCyan, "\r\nSV Cleanup Complete");
                }
                catch (Exception ex)
                {
                    _outputWriter.WriteLineColored(
                        Color.Red, string.Format("SV Cleanup Failed: {0}", ex.Message));
                    Program.LogDbg(ex.ToString());
                }
            }
        }

        private void toolStripMenuReinstall_Click(object sender, EventArgs e)
        {
            FlagInstalledAddons();
            InstallUpdateCheckedAddons(ExternalMode.AUTO, true, true);
        }

        private void toolStripMenuShowCategory_Click(object sender, EventArgs e)
        {
            Settings.Default.ShowCategoryColumn = !Settings.Default.ShowCategoryColumn;
            Settings.Default.Save();


            ResizeListViewColumns();
        }


        private void toolStripMenuUninstallCurrent_Click(object sender, EventArgs e)
        {
            UninstallItems(GetSelectedItems());
        }

        private void toolStripOpenChangeSummaryLog_Click(object sender, EventArgs e)
        {
            webView.AllowNavigation = true;
            webView.DocumentText = File.ReadAllText(CHANGE_SUMMARY_LOG);
            toolButtonHTML.PerformClick();
        }

        private void toolStripOpenForumThread_Click(object sender, EventArgs e)
        {
            string addon_name = GetSelectedAddons()[0].Text;
            string url =
                WowAceFilesServer.GetComments(WowAceFilesServer.FilesLookup[addon_name]);

            if (url != null)
            {
                ShellOpenURL(url);
            }
        }

        private void toolStripOpenUpdateLog_Click(object sender, EventArgs e)
        {
            LoadTextFileInOutputWindow(UPDATE_LOG);
        }


        // Parnic - added the ability to find-as-you-type for names and descriptions optionally
        private void txtSearch_TextChanged(object sender, EventArgs e)
        {
            if (!txtSearch.Enabled)
            {
                return;
            }

            //input

            if (categorybox.SelectedIndex == 0)
            {
                selectedCat = Resources.NoCategoryFilter;
            }
            else if (categorybox.SelectedIndex > 0)
            {
                selectedCat = categorybox.SelectedItem.ToString();
            }
            //input

            // in case this was called from RefreshList...don't do anything when we're refreshing except clear the full list
            if (_isLoading)
            {
                ClearBuildCache();
                return;
            }


            // if this is the first time we've typed in the box after a refresh, populate the full addon list with the list view's contents
            PrepBuildCache();

            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += delegate(object args, DoWorkEventArgs bgE)
                                 {
                                     // if we're emptying the search box, just restore the full list
                                     if ((string.IsNullOrEmpty(txtSearch.Text) &&
                                          _fullAddonList.Length > 0) &&
                                         selectedCat == Resources.NoCategoryFilter)
                                     {
                                         bgE.Result = _fullAddonList;
                                     }
                                     else
                                     {
                                         List<ListViewItem> toBeKept =
                                             new List<ListViewItem>();
                                         // checked regex vs .Contains and regex is empirically faster + it's cleaner for ignoring case
                                         Regex r =
                                             new Regex(txtSearch.Text, RegexOptions.IgnoreCase);

                                         // find matching names and descriptions based on what the user wants to see
                                         foreach (ListViewItem item in _fullAddonList)
                                         {
                                             if (selectedCat == Resources.NoCategoryFilter ||
                                                 selectedCat ==
                                                 item.SubItems[INDEX_ITEMCAT].Text)
                                             {
                                                 if ((chkSearchNames.Checked &&
                                                      r.IsMatch(
                                                          item.SubItems[INDEX_ITEMNAME].Text)) ||
                                                     (chkSearchDescs.Checked &&
                                                      r.IsMatch(
                                                          item.SubItems[INDEX_ITEMDESC].Text)))
                                                 {
                                                     toBeKept.Add(item);
                                                 }
                                             }
                                         }

                                         bgE.Result = toBeKept.ToArray();
                                     }
                                 };

            // pretty much copied from RefreshList
            worker.RunWorkerCompleted +=
                delegate(object bgSender, RunWorkerCompletedEventArgs bgE)
                    {
                        lock (oSearchLock)
                        {
                            // make sure to remove this worker from the queue and see if anyone else is up next to run
                            searchQueue.Dequeue();
                            if (CheckSearchQueue() == false)
                            {
                                return;
                            }
                        }

                        try
                        {
                            ListViewItem[] items = bgE.Result as ListViewItem[];
                            RebuildList(ref items);
                            if (currentListView != null && currentListView.VirtualMode)
                            {
                                RebuildVirtualLists(ref items);
                            }
                            ResizeListViewColumns();
                        }
                        catch (Exception e2)
                        {
                            Program.LogDbg(e2.ToString());
                        }
                    };

            lock (oSearchLock)
            {
                if (searchQueue.Count <= 2)
                {
                    // add this worker to the search queue and see if it's his turn to run
                    searchQueue.Enqueue(worker);
                }

                CheckSearchQueue();
            }
        }

        private void professionalToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ToolStripManager.RenderMode = ToolStripManagerRenderMode.Professional;
        }

        private void reinstallToolStripMenuItemReinstallCurrent_Click(
            object sender, EventArgs e)
        {
            InstallUpdateAddons(GetSelectedItems(), ExternalMode.AUTO, true, true);
        }

        private void reloadIndexToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _outputWriter.Clear();
            _outputWriter.WriteLine(Resources.BypassingCache +
                                    Settings.Default.AceFilesPath);

            WowAceFilesServer.CacheDirty = true;
            RefreshList();
        }

        private void showGroupsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            showGroupsToolStripMenuItem.Checked =
                _addonListView.ShowGroups = !_addonListView.ShowGroups;
            if (!_addonListView.ShowGroups)
            {
                _status.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
                _status2.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
                _status3.AutoResize(ColumnHeaderAutoResizeStyle.ColumnContent);
            }
            else
            {
                _status.Width = 0;
                _status2.Width = 0;
                _status3.Width = 0;

                ResetListViewGroups();
            }
            ResizeListViewColumns();
            SortListViewItems();
        }

        private void undoLastUpdate_Click(object sender, EventArgs e)
        {
            OpenFileDialog fd = new OpenFileDialog();

            fd.CheckFileExists = true;
            fd.AutoUpgradeEnabled = true;
            fd.Title = "Load Addon Snapshot";
            fd.InitialDirectory = WowEnvironment.BackupDirectory;
            fd.DefaultExt = "*.gz";
            DialogResult dr = fd.ShowDialog();

            if (dr == DialogResult.OK)
                LoadSnapshot(fd.FileName);
        }

        private void LoadSnapshot(string path)
        {
            if (
                MessageBox.Show(this,
                                Resources.ThisWillDeleteAllYour,
                                Resources.Confirm,
                                MessageBoxButtons.YesNo) != DialogResult.Yes)
            {
                return;
            }

            FileInfo fi = new FileInfo(path);
            if (!fi.Exists)
                return;

            StreamReader sr = new StreamReader(fi.FullName);
            Stream gzi = Compression.OpenGZipInputStream(sr.BaseStream);
            XmlDocument x = new XmlDocument();

            using (gzi)
                x.Load(gzi);

            XmlNodeList addons = x.DocumentElement.ChildNodes;

            toolButtonOutput.PerformClick();

            _outputWriter.WriteLineColored(Color.Red, "*** Snapshot Load Started ***");
            
            List<string> items = new List<string>();
            XmlSerializer _AddonItemSerializer = new XmlSerializer(typeof(rssAddonItem));

            WowAceFilesServer.UpdateIndexFile();

            foreach (XmlNode node in addons)
            {
                string name = WowAceFilesServer.GetNameFromSource(node);

                XmlReader xnr = new XmlNodeReader(node);

                rssAddonItem item = (rssAddonItem)_AddonItemSerializer.Deserialize(xnr);

                if (item != null)
                {
                    VersionNumber ver = WowAceFilesServer.GetAddonRevision(item);
                    if (ver.Externals == VersionNumber.ExternalsType.WITH)
                        WowAceFilesServer.WithExtFilesLookup[name] = item;
                    else if (ver.Externals == VersionNumber.ExternalsType.WITHOUT)
                        WowAceFilesServer.WithoutExtFilesLookup[name] = item;

                    items.Add(name);
                }
            }
            _outputWriter.WriteLine("");

            backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_RunWorkerCompleted;
            backgroundWorker1.RunWorkerCompleted += backgroundWorker1_Snapshot_RunworkerCompleted; 

            InstallUpdateAddons(items, ExternalMode.AUTO, Settings.Default.DeleteBeforeExtracting, true);

        }

        void backgroundWorker1_Snapshot_RunworkerCompleted(object o, RunWorkerCompletedEventArgs e)
        {
             backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
             backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_Snapshot_RunworkerCompleted;

             _outputWriter.WriteLine();
             _outputWriter.WriteLineColored(Color.Red, "*** Snapshot Load Completed ***");
             _outputWriter.WriteLine();

             WowAceFilesServer.UpdateIndexFile(true);

             RefreshList();
        }

        private void uninstallMarkedAddonsToolStripMenuItem_Click(
            object sender, EventArgs e)
        {
            IEnumerable<string> items = GetCheckedItems();
            if (items != null)
            {
                UninstallItems(items);
            }
        }

        private void unmarkAllToolStripMenuItem_Click(object sender, EventArgs e)
        {
            _addonListView.BeginUpdate();
            _isInserting = true;

            foreach (ListViewItem item in
                new ListView.CheckedListViewItemCollection(_addonListView))
                item.Checked = false;


            currentListView.RedrawItems(0, currentListView.Items.Count - 1, false);
            _isInserting = false;
            _addonListView.EndUpdate();

            UpdateCheckedItemStatusLabel();
        }

        private void updateAllInstalledAddonsToolStripMenuItem_Click(
            object sender, EventArgs e)
        {
            FlagInstalledAddons();
            InstallUpdateCheckedAddons(ExternalMode.AUTO);
        }

        /*
        private void UpdateApplication()
        {
            try
            {
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
                    // ad.CheckForUpdateCompleted += new CheckForUpdateCompletedEventHandler(ad_CheckForUpdateCompleted);
                    // ad.CheckForUpdateProgressChanged += new DeploymentProgressChangedEventHandler(ad_CheckForUpdateProgressChanged);

                    ad.CheckForUpdateAsync();
                }
            }
            catch (Exception)
            {
            }
        }
*/

        private void updateAvailableToolStripMenuItem_Click(object sender, EventArgs e)
        {
            IsRestartRequired = true;
        }

        private void viewChangelogToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string addonName = GetSelectedAddons()[0].Text;


            string url =
                string.Format("http://fish.wowace.com/changelog/WowAce/trunk/{0}?%40hideEmptyDirectories=Y", addonName);

            webView.AllowNavigation = true;
            webView.Url = new Uri(url);
            toolButtonHTML.PerformClick();

            return;

#if false
            rssAddonItem addonSource = WowAceFilesServer.WithoutExtFilesLookup[addonName];

            VersionNumber remoteRev = WowAceFilesServer.GetAddonRevision(addonSource);
            string localZipPath =
                Path.Combine(tempDir,
                             WowAceFilesServer.GetZipFileName(addonName, remoteRev));

            using (new TextWriterMessageWrapper("Downloading Changelog...", _outputWriter)
                )
            {
                WowAceFilesServer.DownloadAddon(addonSource, localZipPath);

                string changeLogFileName =
                    String.Format("{0}/Changelog-{2}-r{1}.txt",
                                  addonName,
                                  remoteRev,
                                  addonName);
                Program.LogDbg("Changelog: " + changeLogFileName);

                _outputWriter.Write("unzipping...");
                FastZip zipFile = new FastZip();
                zipFile.ExtractZip(localZipPath, tempDir, changeLogFileName);
                string pathLog = Path.Combine(tempDir, changeLogFileName);
                if (!File.Exists(pathLog))
                {
                    changeLogFileName =
                        String.Format("{0}/Changelog-r{1}.txt", addonName, remoteRev);
                    pathLog = Path.Combine(tempDir, changeLogFileName);
                    Program.LogDbg("Changelog: " + changeLogFileName);
                    zipFile.ExtractZip(localZipPath, tempDir, changeLogFileName);
                }
                if (File.Exists(Path.Combine(tempDir, changeLogFileName)))
                {
                    _outputWriter.Write("reading...");
                    string changeLogContent;
                    using (StreamReader reader = new StreamReader(pathLog))
                        changeLogContent = reader.ReadToEnd();
                    new ChangelogViewer(addonName, remoteRev, changeLogContent).ShowDialog
                        (this);
                }
            }
#endif
        }

        private void viewToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            if (currentListView != null)
            {
                showGroupsToolStripMenuItem.Enabled = !currentListView.VirtualMode;

                showGroupsToolStripMenuItem.Checked =
                    currentListView.VirtualMode ? false : currentListView.ShowGroups;
            }
            toolStripOpenChangeSummaryLog.Enabled = File.Exists(CHANGE_SUMMARY_LOG);
            toolStripOpenUpdateLog.Enabled = File.Exists(UPDATE_LOG);
            openDiagnosticLog.Visible = Settings.Default.DiagnosticLogging;
            toolStripMenuShowCategory.Checked = Settings.Default.ShowCategoryColumn;
            toolStripMenuItemOpenAppDir.Visible = Settings.Default.DiagnosticLogging;
        }

        private void webBrowser1_ControlAdded(object sender, ControlEventArgs e)
        {
            Program.LogDbg(e.ToString());
        }

        private void webBrowser1_ControlRemoved(object sender, ControlEventArgs e)
        {
            Program.LogDbg(string.Format("Browser: ControlRemoved: {0}", e));
        }

        private void webBrowser1_DocumentCompleted(
            object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            Program.LogDbg(string.Format("Browser: DocComplete {0}", e.Url));

            if (e.Url == ADS_PAGE_URL)
                webBrowser1.AllowNavigation = false;
        }

        private void webBrowser1_FileDownload(object sender, EventArgs e)
        {
            Program.LogDbg("Browser: File Downloaded");
        }

        private void webBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            if (e.Url.Equals("about:blank")) return;

            string subjectString = webBrowser1.DocumentText;
            string resultString = null;
            try {
	            resultString = Regex.Replace(subjectString, "<SCRIPT[^>]*>(.*?)</SCRIPT>", "", RegexOptions.Singleline | RegexOptions.IgnoreCase);
                resultString = Regex.Replace(resultString, "(</?NOSCRIPT>)", "", RegexOptions.Singleline | RegexOptions.IgnoreCase);
            }
            catch (ArgumentException ex)
            {
	            Program.LogErr(ex.ToString());

                return;
            }

            Program.LogDbg(string.Format("Browser: At <{0}>", e.Url));
            Program.LogDbg(string.Format("Browser: HTML <{0}>", webBrowser1.DocumentText));

            if (resultString != null)
            {
                webBrowser1.AllowNavigation = true;
                webBrowser1.DocumentText = resultString;
                webBrowser1.AllowNavigation = false;
            }
            Program.LogDbg(string.Format("Browser: Filtered HTML <{0}>", resultString));

        }

        private void webBrowser1_Navigating(
            object sender, WebBrowserNavigatingEventArgs e)
        {
            Program.LogDbg(
                string.Format("Navigating: <{0}> <{1}>", e.Url, e.TargetFrameName));
        }

        private void webBrowser1_NewWindow(object sender, CancelEventArgs e)
        {
            Program.LogDbg(string.Format("Browser: New Window Creation Detected"));
        }

        private void webBrowser1_ProgressChanged(
            object sender, WebBrowserProgressChangedEventArgs e)
        {
            Program.LogDbg(
                string.Format("Browser: Progress {0} / {1}",
                              e.CurrentProgress,
                              e.MaximumProgress));
        }

        private void withExternalsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            InstallUpdateCheckedAddons(ExternalMode.WITH);
        }

        private void withoutExternalsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            InstallUpdateCheckedAddons(ExternalMode.WITHOUT);
        }

        public static void AddBandwidthUsed(long amt)
        {
            Interlocked.Add(ref _totalBandwidth, amt);
        }

        public void UpdateIndexProgress(long totalBytes, long recievedBytes)
        {
            try
            {
                StatusText =
                    String.Format(Resources.DownloadingIndex,
                                  recievedBytes/1024,
                                  totalBytes/1024);
            }
            catch (Exception e)
            {
                Program.LogDbg(e.ToString());
            }
        }

        public static void wc_DownloadProgressChanged(
            object sender, DownloadProgressChangedEventArgs e)
        {
            indexCachePercent = e.ProgressPercentage/2;
            indexCacheTotalBytes = e.TotalBytesToReceive;
            indexCacheRecievedBytes = e.BytesReceived;

            if (e.ProgressPercentage == 100)
            {
                AddBandwidthUsed(e.BytesReceived);
            }

            MainForm self = ActiveForm as MainForm;
            if (self != null)
            {
                self.UpdateIndexProgress(indexCacheTotalBytes + indexCacheTotalBytes2,
                                         indexCacheRecievedBytes +
                                         indexCacheRecievedBytes2);
            }
        }

        public static void wc2_DownloadProgressChanged(
            object sender, DownloadProgressChangedEventArgs e)
        {
            indexCachePercent2 = e.ProgressPercentage/2;
            indexCacheTotalBytes2 = e.TotalBytesToReceive;
            indexCacheRecievedBytes2 = e.BytesReceived;

            MainForm self = ActiveForm as MainForm;

            if (e.ProgressPercentage == 100)
            {
                AddBandwidthUsed(e.BytesReceived);
            }

            if (self != null)
            {
                self.UpdateIndexProgress(indexCacheTotalBytes + indexCacheTotalBytes2,
                                         indexCacheRecievedBytes +
                                         indexCacheRecievedBytes2);
            }
        }

        internal void DefaultsConfiguration()
        {
            ApplicationTitle = Settings.Default.AceFilesPath;

            toolStripBandwidthUsed.Text = FormatBandwidth(TotalBandwidth);

            // Standalone = without externals
            if (Settings.Default.DefaultUpdateModeWithExternals)
            {
                WowAceFilesServer.WithExternals = true;
                toolStripStatusExternalMode.Text = "Default Mode: Externals";
            }
            else
            {
                WowAceFilesServer.WithExternals = false;
                toolStripStatusExternalMode.Text = "Default Mode: No Externals";
            }
        }

        internal static void wc_DownloadFileCompleted(
            object sender, AsyncCompletedEventArgs e)
        {
            MainForm self = ActiveForm as MainForm;
            if (e.Error != null)
            {
                Program.LogErr(e.Error.ToString());
                if (self != null)
                {
                    self._outputWriter.WriteLine(Resources.ErrorDuringDownload, e.Error);
                }
            }
        }

        internal static void wc2_DownloadFileCompleted(
            object sender, AsyncCompletedEventArgs e)
        {
            MainForm self = ActiveForm as MainForm;
            if (e.Error != null)
            {
                if (self != null)
                {
                    self._outputWriter.WriteLine(Resources.ErrorDuringDownload, e.Error);
                }
            }
        }

        private void AddCategory(ToolStripComboBox c, string text)
        {
            if (c == null || c.GetCurrentParent() == null
                || c.GetCurrentParent().IsDisposed)
                return;

            if (c.GetCurrentParent().InvokeRequired)
            {
                AddCategoryCallback d = AddCategory;
                BeginInvoke(d, new object[] {c, text});
            }
            else
            {
                if (c.Items.Count == 0)
                {
                    c.Items.Add(Resources.NoCategoryFilter);
                }

                if (c.Items.Contains(text))
                {
                }
                else
                {
                    c.Items.Add(text);
                }
            }
        }

        // Parnic - handles people typing faster than the worker can populate the listview
        private bool CheckSearchQueue()
        {
            // Peek will throw an exception if Count is 0, so let's avoid that :P
            if (searchQueue.Count == 0)
            {
                return true;
            }

            // try to run the next worker
            BackgroundWorker bgWorker = searchQueue.Peek();
            if (!bgWorker.IsBusy)
            {
                bgWorker.RunWorkerAsync();
            }

            return false;
        }

        public static int CvtLvt(ListViewItem pf)
        {
            return pf.Index;
        }


        private static IList<int> GetSelectedIndexes(ListView listView)
        {
            // Set to the selection in the virtual list
            IList<int> indexes;


            int[] a = new int[listView.SelectedIndices.Count];
            listView.SelectedIndices.CopyTo(a, 0);
            indexes = a;

            return indexes;
        }


        private void DoVersionCheck()
        {
            if (Program.bNoVersionCheck)
            {
                return;
            }

            AssemblyName assLocal = Assembly.GetExecutingAssembly().GetName();


            Program.LogDbg("Assembly: " + assLocal.FullName);
            Version verLocal = assLocal.Version;

            try
            {
                if (ApplicationDeployment.IsNetworkDeployed)
                {
                    ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;

                    if (Settings.Default.LastVersionUsed != ad.CurrentVersion.ToString())
                    {
                        NewVersion(ad.CurrentVersion);

                        Settings.Default.LastVersionUsed = ad.CurrentVersion.ToString();
                        Settings.Default.Save();
                    }
                    _outputWriter.WriteLine(Resources.WAUVersion, ad.CurrentVersion, verLocal);
                    ad.CheckForUpdateCompleted +=
                        CurrentDeployment_CheckForUpdateCompleted;

                    ad.UpdateCompleted +=
                        CurrentDeployment_UpdateCompleted;
                }
                else
                {
                    _outputWriter.WriteLineColored(Color.Red, Resources.WARNINGObnox);
                    _outputWriter.WriteLine();

                    _outputWriter.WriteLine(Resources.ThisVersionWillNotAutoUpdate);

                    _outputWriter.WriteLine();
                    _outputWriter.WriteLineColored(Color.Red, Resources.WARNINGObnox);

                    //_outputWriter.WriteLine();
                    //_outputWriter.WriteLine();
                    //_outputWriter.Write(Resources.VersionCheck);

                    //Version verLatest = GetCurrentVersion();
                    //bool bUpdate = verLocal < verLatest;
                    //bCheckedVersion = true;

                    //if (bUpdate)
                    //{
                    //    _outputWriter.WriteLine(Resources.UpdateAvailable, verLatest);

                    //    BackgroundWorker worker = new BackgroundWorker();
                    //    worker.DoWork += delegate {
                    //                         DialogResult rc =
                    //                             MessageBox.Show(
                    //                                 Resources.AnUpdatedVersion,
                    //                                 Resources.UpdateAvailable2,
                    //                                 MessageBoxButtons.YesNo,
                    //                                 MessageBoxIcon.Question,
                    //                                 MessageBoxDefaultButton.Button1);

                    //                         if (rc == DialogResult.Yes)
                    //                         {
                    //                             ShellOpenURL(DOWNLOAD_PAGE_URL_SF);
                    //                         }
                    //                     };

                    //    worker.RunWorkerAsync();
                    //}
                    //else
                    //{
                    //    _outputWriter.WriteLine(Resources.RunningLatestVersion, verLocal);
                    //}
                }
            }
            catch (Exception e)
            {
                _outputWriter.WriteLine("Error");
                Program.LogErr(e.ToString());
            }
        }

        private static void NewVersion(Version version)
        {
            Program.LogDbg(string.Format("Detected new version {0} running for first time",
                                         version.ToString(4)));
        }

        private static void output(TextWriter tw, string s)
        {
            tw.WriteLine(s);
            Program.LogDbg(s);
        }

        private void DownloadAndExtract(
            string addonName,
            ExternalMode skipExternals,
            bool skipVersionCheck,
            bool deleteBeforeExtract,
            ICollection<string> list,
            ICollection<string> listDone,
            ICollection<string> listCurrent,
            TextWriter outputWriter,
            Object oLock)
        {
            string addonPath = WowEnvironment.AddonsDirectory;
            string tempDir = FileSystem.TempDirectory;

            lock (addonName)
            {
                VersionNumber localRev = WowEnvironment.GetAddonRevision(addonName);

                rssAddonItem addonSource;
                ExternalMode mode = skipExternals;
                if (mode == ExternalMode.AUTO)
                {
                    if (localRev.Externals != VersionNumber.ExternalsType.UNKNOWN)
                    {
                        if (localRev.Externals == VersionNumber.ExternalsType.WITH)
                        {
                            mode = ExternalMode.WITH;
                        }
                        else
                        {
                            mode = ExternalMode.WITHOUT;
                        }
                    }
                }

                if (mode == ExternalMode.WITHOUT)
                {
                    addonSource = WowAceFilesServer.WithoutExtFilesLookup[addonName];
                }
                else if (mode == ExternalMode.WITH)
                {
                    addonSource = WowAceFilesServer.WithExtFilesLookup[addonName];
                }
                else
                {
                    addonSource = WowAceFilesServer.FilesLookup[addonName];
                }

                if (addonSource == null)
                {
                    Program.LogDbg(string.Format("ERROR: Addon Source Is Null {0}",
                                                 addonName));
                    _outputWriter.WriteLineColored(Color.Red,
                                                   String.Format(
                                                       Resources.ErrorDuringUpdate,
                                                       addonName));
                }

                VersionNumber remoteRev = WowAceFilesServer.GetAddonRevision(addonSource);
                Program.LogDbg(
                    String.Format("Mode: {3}:{0} Update: {1:E} -> {2:E}",
                                  mode,
                                  localRev,
                                  remoteRev,
                                  addonName));

                ChangeLog.AddAddon(addonName, localRev, remoteRev);

                if (remoteRev == VersionNumber.NO_VERSION)
                {
                    _outputWriter.WriteLine(
                        String.Format(Resources.HasNoPublicVersionsSkipping, addonName));
                    output(outputWriter,
                           String.Format(Resources.HasNoPublicVersionsSkipping, addonName));
                    return;
                }

                string installPath = WowEnvironment.GetAddonDirectory(addonName);
                string localZipPath =
                    Path.Combine(tempDir,
                                 WowAceFilesServer.GetZipFileName(addonName, remoteRev));

                if (skipVersionCheck || (remoteRev > localRev))
                {
                    try
                    {
                        output(outputWriter,
                               String.Format(Resources.UpdatingToRev, addonName, remoteRev));
                        FileSystem.EnsureDirExists(tempDir);
                        FileSystem.EnsureDirExists(addonPath);

                        string addonURL = WowAceFilesServer.GetZipFileUrl(addonSource);
                        output(outputWriter, addonURL);
                        using (
                            new TextWriterMessageWrapper(Resources.Downloading, outputWriter)
                            )
                            WowAceFilesServer.DownloadAddon(addonSource, localZipPath);

                        if (Directory.Exists(installPath))
                        {
                            LinkedList<string> uninstalledList = new LinkedList<string>();
                            if (deleteBeforeExtract)
                            {
                                WowEnvironment.UninstallAddon(addonName,
                                                              outputWriter,
                                                              uninstalledList,
                                                              oLock);
                            }
                            else
                            {
                                List<string> zipfiles = Compression.GetZipContentsList(addonName, localZipPath);

                                WowEnvironment.RepackAddon(addonName,
                                                           outputWriter,
                                                           uninstalledList,
                                                           zipfiles,
                                                           oLock, true);
                            }

                            lock (oLock)
                            {
                                foreach (string s in uninstalledList)
                                {
                                    if (WowAceFilesServer.FilesLookup.ContainsKey(s))
                                    {
                                        Program.LogDbg(string.Format("Marking as non updated: {0}", s));
                                        listDone.Remove(s);

                                        if (listCurrent.Contains(s))
                                            Program.LogDbg("WARN: Uninstalled Addon Which Is In Progress ");
                                    }
                                }
                            }
                        }

                        WowEnvironment.InstallAddon(localZipPath,
                                                    addonName,
                                                    addonSource,
                                                    outputWriter,
                                                    list,
                                                    oLock);

                        if (
                            WowEnvironment.SupportsPackOperation(
                                WowEnvironment.PackOperation.PACK, addonName))
                        {
                            WowEnvironment.ValidatePackage(addonName, outputWriter);
                        }

                        using (
                            new TextWriterMessageWrapper(Resources.DeletingZIPFile,
                                                         outputWriter))
                            File.Delete(localZipPath);

                        Interlocked.Increment(ref _updateCount);
                        _outputWriter.WriteLineColored(Color.Green,
                                                       String.Format(
                                                           Resources.UpdatedToRev1E,
                                                           addonName,
                                                           remoteRev));
                    }
                    catch (Exception e)
                    {
                        Interlocked.Increment(ref _errorCount);
                        _outputWriter.WriteLineColored(Color.Red,
                                                       String.Format(
                                                           Resources.ErrorDuringUpdate,
                                                           addonName));

                        outputWriter.WriteLine("- Error:");
                        outputWriter.WriteLine(e.ToString());

                        Program.LogErr(e.ToString());

                        lock (oLock)
                        {
                            listCurrent.Remove(addonName);

                            // TODO - This can cause infinite retries, fix later
                            if (!list.Contains(addonName))
                                list.Add(addonName);
                        }

                        return;
                    }
                }
                else
                {
                    outputWriter.WriteLine(
                        String.Format(Resources.AlreadyAtRev1ESkipping,
                                      addonName,
                                      remoteRev));
                }

                if (Program.bDeps || Settings.Default.AutoDeps)
                {
                    lock (oLock)
                    {
                        try
                        {
                            XmlNode addonSourceInstalled =
                                WowEnvironment.GetAddonSource(addonName).FirstChild;
                            if (addonSourceInstalled != null)
                            {
                                foreach (string a in
                                    WowAceFilesServer.GetAddonDependancies(addonSource))
                                {
                                    if (!listDone.Contains(a) && !list.Contains(a) &&
                                        !listCurrent.Contains(a))
                                    {
                                        _outputWriter.WriteLineColored(Color.Purple,
                                                                       string.Format(
                                                                           Resources.AddingDependency01,
                                                                           addonName,
                                                                           a));
                                        list.Add(a);
                                    }
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            Program.LogErr(e.ToString());
                        }
                    }
                }

                lock (oLock)
                {
                    listCurrent.Remove(addonName);

                    if (list.Contains(addonName))
                        Program.LogDbg(
                            string.Format("WARN: {0} requed during processing, not adding it to the completed list.",
                                          addonName));
                    else
                        listDone.Add(addonName);
                }
            }

            outputWriter.Dispose();
        }




        private void EnableUserInteraction(bool value)
        {
            _isInserting = !value;
            _editMenuItem.Enabled = value;
            mirrorsToolStripMenuItem.Enabled = value;
            toolStripMenuItemReinstallMarked.Enabled = value;
            toolStripMenuItemSVCleanup.Enabled = value;
            toolStripMenuReinstall.Enabled = value;
            toolStripSearchPanel.Enabled = value;
            uninstallMarkedAddonsToolStripMenuItem.Enabled = value;
            updateAllInstalledAddonsToolStripMenuItem.Enabled = value;
            viewToolStripMenuItem.Enabled = value;
            withExternalsToolStripMenuItem.Enabled = value;
            withoutExternalsToolStripMenuItem.Enabled = value;
            autoExternalsToolStripMenuItem.Enabled = value;
            toolStripCommands.Enabled = value;
            woWInstallsToolStripMenuItem.Enabled = value;

            if (value)
            {
                StatusText = IdleStatusText;
            }

            ToolStripButton t = value ? _lastChecked : null;
            if (value)
            {
                toolStripTabPanel.Enabled = value;
            }

            if (Settings.Default.DisplayOutputDuringUpdate)
            {
                if (t == null)
                {
                    toolButtonUpdated.PerformClick();
                }
                else
                {
                    t.PerformClick();
                }
            }

            if (!value)
            {
                toolStripTabPanel.Enabled = value;
            }


            Application.DoEvents();
        }

        private void FlagInstalledAddons()
        {
            _addonListView.BeginUpdate();
            _isInserting = true;

            for (int i = 0; i < _addonListView.Items.Count; i++)
            {
                _addonListView.Items[i].Checked =
                    WowEnvironment.IsInstalled(_addonListView.Items[i].Text);
            }

            if (currentListView != null && currentListView.Items.Count > 0)
            {
                currentListView.RedrawItems(0, currentListView.Items.Count - 1, false);
            }
            _isInserting = false;
            _addonListView.EndUpdate();

            UpdateCheckedItemStatusLabel();
        }

        private static string FormatBandwidth(long nTotalBandwidth)
        {
            const long kb = 1024;
            const long mb = kb*kb;
            const long gb = mb*kb;
            Decimal amt = new Decimal(nTotalBandwidth);
            if (amt/gb > 1)
            {
                return string.Format(Resources.YourBandwidthGB, amt/gb);
            }
            if (amt/mb > 1)
            {
                return string.Format(Resources.YourBandwidthMB, amt/mb);
            }
            if (amt/kb > 1)
            {
                return string.Format(Resources.YourBandwidthKB, amt/kb);
            }

            return string.Format(Resources.YourBandwidthBytes, amt);
        }

        private static string FormatTimespan(ref TimeSpan betweentime)
        {
            string changed;
            if (betweentime.Days > 365)
            {
                changed = ">1 Year";
            }
            else if (betweentime.Days > 180)
            {
                changed = ">180 Days";
            }
            else if (betweentime.Days > 90)
            {
                changed = ">90 Days";
            }
            else if (betweentime.Days > 30)
            {
                changed = ">30 Days";
            }
            else if (betweentime.Days >= 14)
            {
                changed = string.Format("{0} Weeks", betweentime.Days/7);
            }
            else if (betweentime.Days > 0)
            {
                changed = string.Format("{0} Days", betweentime.Days);
            }
            else if (betweentime.Hours > 0)
            {
                changed = string.Format("{0} Hours", betweentime.Hours);
            }
            else if (betweentime.Minutes > WowAceFilesServer.CACHE_MIN_MINUTES)
            {
                changed = string.Format("{0} Min", betweentime.Minutes);
            }
            else
            {
                changed = string.Format("<{0} Min", WowAceFilesServer.CACHE_MIN_MINUTES);
            }
            return changed;
        }

/*
        private static Version GetCurrentVersion()
        {
            Version v = null;

            try
            {
                using (WebClient wc = GetWebConfiguredWebClient())
                {
                    string latestString =
                        wc.DownloadString(WOWACEUPDATER_LATEST_VERSION_FILE_URL);

                    v = new Version(latestString);
                }
            }
            catch (Exception e)
            {
                Program.LogDbg(e.ToString());
            }

            return v;
        }
*/


        private List<string> GetSelectedItems()
        {
            List<string> selectedAddons = new List<string>();

            if (currentListView != null)
            {
                foreach (int idx in GetSelectedIndexes(currentListView))
                    selectedAddons.Add(currentListView.Items[idx].Text);
            }
            return selectedAddons;
        }

        private List<ListViewItem> GetSelectedAddons()
        {
            List<ListViewItem> selectedAddons = new List<ListViewItem>();

            if (currentListView != null)
            {
                foreach (int idx in GetSelectedIndexes(currentListView))
                    selectedAddons.Add(currentListView.Items[idx]);
            }
            return selectedAddons;
        }


/*
        private static WebClient GetWebConfiguredWebClient()
        {
            WebClient result = new WebClient();
            result.Headers.Add("User-Agent",
                               String.Format("{0}/{1}",
                                             Application.ProductName,
                                             Application.ProductVersion));
            return result;
        }
*/

        private void InitMonkey()
        {
            UpdateCheckMonkey = new BackgroundWorker();
            UpdateCheckMonkey.DoWork += MonkeyDo;
        }

        private void InstallUpdateAddons(
            ICollection<string> selectedAddonNames, ExternalMode skipExternals)
        {
            InstallUpdateAddons(selectedAddonNames,
                                skipExternals,
                                Settings.Default.DeleteBeforeExtracting,
                                Settings.Default.SkipVersionCheck);
        }

        private void InstallUpdateAddons(
            ICollection<string> selectedAddonNames,
            ExternalMode externalsMode,
            bool deleteBeforeExtract,
            bool ignoreVersionCheck)
        {
            switch (externalsMode)
            {
                case ExternalMode.WITH:
                    WowAceFilesServer.WithExternals = true;
                    break;

                case ExternalMode.WITHOUT:
                    WowAceFilesServer.WithExternals = false;
                    break;

                case ExternalMode.AUTO:
                    WowAceFilesServer.WithExternals =
                        Settings.Default.DefaultUpdateModeWithExternals;
                    break;
            }

            _updateCount = _errorCount = 0;

            if (selectedAddonNames.Count != 0)
            {
                if (Settings.Default.ConfirmSync && !Program.bNoPrompts)
                {
                    if (
                        MessageBox.Show(this,
                                        Resources.AreYouSureYouWantToInstall,
                                        Resources.Confirm,
                                        MessageBoxButtons.YesNo) != DialogResult.Yes)
                    {
                        return;
                    }
                }

                EnableUserInteraction(false);

                StatusText = Resources.Updating;

                _outputWriter.Clear();
                Program.FlushLog();

                _updateStartTime = DateTime.Now;
                _outputWriter.Write(Resources.UpdateStarted);
                _outputWriter.WriteColored(Color.Blue, externalsMode.ToString());
                _outputWriter.WriteLine(Resources.Externals, _updateStartTime);
                _outputWriter.WriteLine(Resources.TempDirectorySkipVersionChecks,
                                        FileSystem.TempDirectory,
                                        ignoreVersionCheck);
                try
                {
                    if (Settings.Default.CreateBackupFiles)
                    {
                        string backupFile = WowEnvironment.BackupAddonConfiguration();

                        _outputWriter.WriteLineColored(Color.Brown,
                                                       string.Format(
                                                           Resources.
                                                               CurrentAddonSnapshotSavedTo,
                                                           backupFile));
                    }
                }
                catch (Exception e)
                {
                    Program.LogErr(e.ToString());
                }
                toolStripMenuCancelUpdate.Visible = true;

                backgroundWorker1.WorkerReportsProgress = true;
                backgroundWorker1.WorkerSupportsCancellation = true;
                backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
                backgroundWorker1.RunWorkerAsync(
                    new BackgroundWorkerParams(selectedAddonNames,
                                               externalsMode,
                                               ignoreVersionCheck,
                                               deleteBeforeExtract));
            }
        }

        private void InstallUpdateCheckedAddons(ExternalMode skipExternals)
        {
            InstallUpdateCheckedAddons(skipExternals,
                                       Settings.Default.DeleteBeforeExtracting,
                                       Settings.Default.SkipVersionCheck);
        }

        private void InstallUpdateCheckedAddons(
            ExternalMode skipExternals, bool deleteBeforeExtract, bool ignoreVersionCheck)
        {
            List<string> selectedAddonNames = GetCheckedItems();

            InstallUpdateAddons(selectedAddonNames,
                                skipExternals,
                                deleteBeforeExtract,
                                ignoreVersionCheck);
        }

        private List<string> GetCheckedItems()
        {
            //             ListView.CheckedIndexCollection c = 
            //                 new ListView.CheckedIndexCollection(_addonListView);
            List<string> selectedAddonNames = new List<string>();
            foreach (ListViewItem item in _addonListView.Items)
            {
                if (item.Checked)
                {
                    selectedAddonNames.Add(item.Text);
                }
            }
            return selectedAddonNames;
        }

        private void MonkeyDo(object sender, DoWorkEventArgs e)
        {
            ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;

            Program.LogDbg(
                string.Format("MonkeySee: <{0}> <{1}> <{2}>",
                              ad.TimeOfLastUpdateCheck,
                              ad.CurrentVersion,
                              ad.UpdatedVersion));

            if (ad.UpdatedVersion == null) return;
                
            VersionText = ad.UpdatedVersion.ToString(4);

            if (ad.UpdatedVersion != ad.CurrentVersion)
            {
                IsRestartRequired = true;
            }
            else
            {
                TimeSpan delta = DateTime.UtcNow - ad.TimeOfLastUpdateCheck;
                if (!bCheckedVersion || delta.Minutes > 20)
                {
                    try
                    {
                        Program.LogDbg("MonkeyDo");
                        VersionText = Resources.Checking;
                        CheckForUpdates();
                        bCheckedVersion = true;
                    }
                    catch (Exception ex)
                    {
                        Program.LogErr(ex.ToString());
                    }
                }
            }
        }

        public void TOCVersionUpdated()
        {
            if (IsDisposed)
                return;

            if (InvokeRequired)
                BeginInvoke(new TOCVersionUpdatedFunction(TOCVersionUpdated));
            else
            {
                if (!WowEnvironment.LoadOutOfDateAddons)
                {
                    if (MessageBox.Show(this,
                                        "WAU has detected an interface version change. Since you have your game configured to only load addons which have the correct version number, some may fail to load. These addons are displayed with a line drawn through them (strikeout)\n\nWould you like WAU to correct this?",
                                        Resources.Confirm,
                                        MessageBoxButtons.YesNo) == DialogResult.Yes)
                        WowEnvironment.LoadOutOfDateAddons = true;
                }

                RefreshList();
            }
        }


        private void MonkeySee()
        {
            if (!checkedToc)
            {
                checkedToc = true;

                BackgroundWorker worker = new BackgroundWorker();
                worker.DoWork +=
                    delegate(object args, DoWorkEventArgs e) { e.Result = WowEnvironment.GetWoWInterfaceVersion(); };

                worker.RunWorkerCompleted += delegate(object args, RunWorkerCompletedEventArgs e)
                                                 {
                                                     string toc = e.Result as string;
                                                     if (!string.IsNullOrEmpty(toc))
                                                     {
                                                         _safeInterfaceVersion.Text = "TOC: " + toc;

                                                         if (Settings.Default.LastTOCValue != toc)
                                                         {
                                                             Settings.Default.LastTOCValue = toc;
                                                             Settings.Default.Save();

                                                             TOCVersionUpdated();
                                                         }
                                                     }
                                                 };
                worker.RunWorkerAsync();
            }
            if (!_isRestartRequired && ApplicationDeployment.IsNetworkDeployed)
            {
                if (!UpdateCheckMonkey.IsBusy)
                {
                    UpdateCheckMonkey.RunWorkerAsync();
                }
            }
        }

        private ListViewItem[] ParseIndexFile()
        {
            List<ListViewItem> result = new List<ListViewItem>();
            _virtualUpdated.Clear();
            _virtualInstalled.Clear();
            _addonMap.Clear();
            //string[] lines = indexFile.Split('\n');


            SortedDictionary<string, rssAddonItem> remoteLookup =
                WowAceFilesServer.FilesLookup;


            if (remoteLookup == null)
            {
                Program.LogDbg("ERR: The addon list cache is null");
                return null;
            }

            if (!_quiet)
            {
                _outputWriter.Write(Resources.ParsingEntriesInTheIndexFile,
                                    remoteLookup.Keys.Count);
            }

            HandleExtraSVNWorkingCopies();

            uint toc;
            uint.TryParse(Settings.Default.LastTOCValue, out toc);
            bool loadOutOfDate = WowEnvironment.LoadOutOfDateAddons;

            foreach (string addonName in remoteLookup.Keys)
            {
                DateTime publishDate;
                ListViewItem item = new ListViewItem();

                rssAddonItem localAddon = WowEnvironment.GetAddonItem(addonName);
                rssAddonItem remoteAddon = remoteLookup[addonName];

                string strToolTip;

                CultureInfo ciInv = CultureInfo.InvariantCulture;
                publishDate = DateTime.Parse(remoteAddon.pubDate, ciInv);

                DateTime timenow = DateTime.Now;
                TimeSpan betweentime = timenow.Subtract(publishDate);

                string changed = FormatTimespan(ref betweentime);

                VersionNumber localRev = WowEnvironment.GetAddonRevision(addonName);

                if (localAddon != null)
                {
                    strToolTip = localAddon.GetStringTooltip();
                }
                else
                {
                    strToolTip = remoteAddon.GetStringTooltip();
                }

                strToolTip += string.Format(Resources.LocalVersion, localRev);

                item.Text = item.Name = addonName;

                string category = "Unknown";
                if (remoteAddon.category != null)
                {
                    category = remoteAddon.category[0];
                }

                AddCategory(categorybox, category);

                ListViewItem.ListViewSubItem descriptionSubItem =
                    new ListViewItem.ListViewSubItem();

                descriptionSubItem.Text = remoteAddon.description;
                descriptionSubItem.Name = "Description";
                item.SubItems.Add(descriptionSubItem);

                ListViewItem.ListViewSubItem versionSubItem =
                    new ListViewItem.ListViewSubItem();

                versionSubItem.Text = string.Format("{0:e}", localRev);

                //insert
                //                string addonName = _addonListView.SelectedItems[0].Name;

                rssAddonItem addonSource;
                addonSource = WowAceFilesServer.GetCurrentAddonSource(addonName, localRev);

                VersionNumber remoteRev = WowAceFilesServer.GetAddonRevision(addonSource);


                if (localRev != VersionNumber.NO_VERSION && remoteRev > localRev)
                {
                    if (addonSource.stable == true)
                    {
                        item.BackColor = SystemColors.Info;
                        item.ForeColor = SystemColors.InfoText;
                    }
                    else
                    {
                        item.BackColor = SystemColors.InactiveCaption;
                        item.ForeColor = SystemColors.InactiveCaptionText;
                    }

                    strToolTip += string.Format(Resources.UpdatesTo, remoteRev);
                    _virtualUpdated.Add(item);
                }
                versionSubItem.Tag = localRev;
                item.ToolTipText = strToolTip;
                versionSubItem.Name = "Version";
                item.SubItems.Add(versionSubItem);

                //test
                ListViewItem.ListViewSubItem publishDateSubItem =
                    new ListViewItem.ListViewSubItem();

                publishDateSubItem.Text = changed;
                publishDateSubItem.Tag = publishDate; // make sortable
                publishDateSubItem.Name = "PublishDate";
                item.SubItems.Add(publishDateSubItem);

                ListViewItem.ListViewSubItem categorySubItem =
                    new ListViewItem.ListViewSubItem();

                categorySubItem.Text = category;

                categorySubItem.Name = "Category";
                item.SubItems.Add(categorySubItem);

                //insert in list testedit

                ListViewItem.ListViewSubItem statusSubItem =
                    new ListViewItem.ListViewSubItem();

                SetListViewGroup(item, statusSubItem, addonName, true);

                statusSubItem.Name = "Status";

                if (!loadOutOfDate && toc > 0 && addonSource.@interface != toc)
                {
                    item.UseItemStyleForSubItems = true;
                    item.Font = new Font(item.Font, FontStyle.Strikeout);
                }

                item.SubItems.Add(statusSubItem);

                result.Add(item);
            }

            return result.ToArray();
        }

        private static void HandleExtraSVNWorkingCopies()
        {
            if (Settings.Default.SkipSvnWorkingCopies == false)
            {
                foreach (string d in Directory.GetDirectories(WowEnvironment.AddonsDirectory))
                    if (FileSystem.IsSvnWorkingCopy(d) &&
                        !WowAceFilesServer.FilesLookup.ContainsKey(Path.GetFileName(d)))
                    {
                        rssAddonItem item = new rssAddonItem();
                        item.title = Path.GetFileName(d);
                        item.description = "Non wowace SVN working copy";
                        item.pubDate = DateTime.UtcNow.ToString(CultureInfo.InvariantCulture);

                        try
                        {
                            string fname =
                                Path.Combine(Path.Combine(WowEnvironment.AddonsDirectory, d),
                                             ".svn" + Path.DirectorySeparatorChar + "entries");

                            if (File.Exists(fname))
                            {
                                string[] lines = File.ReadAllLines(fname);

                                string ver = lines[3];
                                string url = lines[4];


                                item.version = ver;
                                item.description = string.Format("SVN: Working copy ({0})", url);
                            }
                        }
                        catch (Exception e)
                        {
                            Program.LogDbg(e.ToString());
                        }

                        WowAceFilesServer.WithExtFilesLookup[item.title] = item;
                        WowAceFilesServer.WithoutExtFilesLookup[item.title] = item;
                    }
            }
        }

        private void RefreshList()
        {
            RefreshList(false);
        }

        private void RefreshList(bool quiet)
        {
            _quiet = quiet;
            _isLoading = true;
            canRetryRefresh = true;
            ApplicationTitle = Settings.Default.AceFilesPath;

            if (!_quiet)
            {
                if (WowAceFilesServer.CacheDirty)
                {
                    StatusText = Resources.RetrievingAvailableAddons;
                }
                else
                {
                    StatusText = Resources.UsingCachedListOfAddons;
                }
            }

            _addonListView2.VirtualListSize = 0;
            _addonListView3.VirtualListSize = 0;

            _virtualUpdated.Clear();
            _virtualInstalled.Clear();
            _addonListView.Items.Clear();
            // Parnic - need to clear the search box when the full addon list is updated
            txtSearch.Clear();

            ClearBuildCache();
            categorybox.SelectedText = Resources.NoCategoryFilter;

            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += delegate(object args, DoWorkEventArgs e)
                                 {
                                     try
                                     {
                                         foreach (string d in
                                             Directory.GetDirectories(
                                                 WowEnvironment.AddonsDirectory))
                                         {
                                             if (
                                                 WowEnvironment.SupportsPackOperation(
                                                     WowEnvironment.PackOperation.PACK, d))
                                             {
                                                 WowEnvironment.ValidatePackage(d,
                                                                                _outputWriter);
                                             }
                                         }

                                         ListViewItem[] lvItems = ParseIndexFile();
                                         e.Result = lvItems;
                                     }
                                     catch (DirectoryNotFoundException ex)
                                     {
                                         Program.LogErr(ex.ToString());
                                         StatusText = Resources.ErrorLoadingAddonList;
                                         _outputWriter.WriteLine(
                                             string.Format(Resources.ErrorLoadingAddonList0, ex.Message));
                                     }
                                     catch (WebException ex)
                                     {
                                         Program.LogErr(ex.ToString());
                                         StatusText = Resources.ErrorLoadingAddonList;
                                         _outputWriter.WriteLine(
                                             string.Format(Resources.ErrorLoadingAddonList0, ex.Message));
                                     }
                                     catch (Exception ex)
                                     {
                                         Program.LogErr(ex.ToString());
                                         StatusText = Resources.ErrorLoadingAddonList;
                                         _outputWriter.WriteLine(
                                             string.Format(Resources.ErrorLoadingAddonList0, ex.Message));
                                     }
                                 };

            worker.RunWorkerCompleted +=
                delegate(object sender, RunWorkerCompletedEventArgs e)
                    {
                        try
                        {
                            if (e.Result == null && canRetryRefresh)
                            {
                                BackgroundWorker b = sender as BackgroundWorker;

                                if (b != null)
                                {
                                    b.RunWorkerAsync();
                                    _outputWriter.WriteLine("Auto-retry of addon list load");
                                    canRetryRefresh = false;
                                }

                                return;
                            }
                            _isInserting = true;
                            ListViewItem[] items = e.Result as ListViewItem[];

                            _addonListView.SuspendLayout();
                            if (items != null)
                            {
                                _addonListView.Items.AddRange(items);
                            }

                            SortListViewItems();
                           
                            categorybox.Text = Resources.NoCategoryFilter;

                            UpdateCheckedItemStatusLabel();
                            _addonListView.ResumeLayout();



                            PrepBuildCache();

                            RebuildList(ref _fullAddonList);
                            ResizeListViewColumns();

                            _isLoading = false;
                            StatusText = IdleStatusText;
                            if (!_quiet)
                            {
                                _outputWriter.WriteLine(Resources.Complete);
                            }

                            webBrowser1.AllowNavigation = true;
                            webBrowser1.Url = ADS_PAGE_URL;
                        }
                        catch (Exception ex)
                        {
                            Program.LogErr(ex.ToString());
                            StatusText = Resources.ErrorLoadingAddonList;
                            _outputWriter.WriteLine(string.Format(Resources.ErrorLoadingAddonList0, ex.Message));

                            return;
                        }

                        EnableUserInteraction(true);

                        if (Program.bUpdate)
                        {
                            FlagInstalledAddons();
                            InstallUpdateCheckedAddons(ExternalMode.AUTO);
                        }
                    };

            EnableUserInteraction(false);
            worker.RunWorkerAsync();
        }

        private void ResetListViewGroups()
        {
            DefaultsConfiguration();
            //             SortListViewItems();
            RefreshList(true);
        }

        private void ResizeListViewColumns()
        {
            _addonListView.SuspendLayout();
            try
            {
                //if (c2HW == 0 || c3HW == 0)
                //{
                c2HW = TextRenderer.MeasureText(_addonListView.Columns[2].Text,
                                                _addonListView.Font).Width;

                c3HW = TextRenderer.MeasureText(_addonListView.Columns[3].Text,
                                                _addonListView.Font).Width;

                //}
                _addonListView.Columns[0].AutoResize(
                    ColumnHeaderAutoResizeStyle.ColumnContent);

                if (_addonListView.Columns[3].Width < c3HW)
                {
                    _addonListView.Columns[3].Width = c3HW;
                }
                if (_addonListView.Columns[2].Width < c2HW)
                {
                    _addonListView.Columns[2].Width = c2HW;
                }
                _addonListView.Columns[2].AutoResize(
                    ColumnHeaderAutoResizeStyle.ColumnContent);

                _addonListView.Columns[3].AutoResize(
                    ColumnHeaderAutoResizeStyle.ColumnContent);

                //_addonListView.ResumeLayout(true);
                //_addonListView.SuspendLayout();


                if (Settings.Default.ShowCategoryColumn)
                {
                    _category.AutoResize(
                        ColumnHeaderAutoResizeStyle.ColumnContent);
                    _category2.AutoResize(
                        ColumnHeaderAutoResizeStyle.ColumnContent);
                    _category2.AutoResize(
                        ColumnHeaderAutoResizeStyle.ColumnContent);
                }
                else
                {
                    _category.Width = 0;
                    _category2.Width = 0;
                    _category3.Width = 0;
                }
                _addonListView.ResumeLayout(true);
                int otherColsWidth = 0;
                foreach (ColumnHeader header in _addonListView.Columns)
                {
                    if (header != _descriptionHeader)
                    {
                        otherColsWidth += header.Width;
                    }
                }
                _addonListView.Columns[1].Width = _addonListView.ClientSize.Width -
                                                  otherColsWidth;
            }
            catch (Exception e)
            {
                Program.LogDbg(e.ToString());
            }


            foreach (ColumnHeader header in _addonListView.Columns)
            {
                _addonListView2.Columns[header.Index].Width = header.Width;
                _addonListView3.Columns[header.Index].Width = header.Width;
            }

            int ci = _descriptionHeader.Index;

            if (_addonListView3.Items.Count > 0)
            {
                ColumnHeader c = _addonListView3.Columns[ci];
                SizeLastHeader(ref c);
            }
            if (_addonListView2.Items.Count > 0)
            {
                ColumnHeader c = _addonListView2.Columns[ci];
                SizeLastHeader(ref c);
            }
        }

        private static void SizeLastHeader(ref ColumnHeader c)
        {
            if (c != null)
            {
                int diff = (c.ListView.Location.X + c.ListView.ClientSize.Width) -
                           c.ListView.GetItemRect(0).Right;

                c.Width += diff;
            }
        }

        private void SetListViewGroup(
            ListViewItem item,
            ListViewItem.ListViewSubItem statusSubItem,
            string addonName,
            bool bBuildVirtualLists)
        {
            try
            {
                if (_addonMap.ContainsKey(addonName))
                {
                    _addonMap.Remove(addonName);
                }

                if (Settings.Default.IgnoredAddons != null &&
                    Settings.Default.IgnoredAddons.Contains(item.Name))
                {
                    item.Group = _addonListView.Groups[statusSubItem.Text = "Ignored"];
                }
                else if (Directory.Exists(WowEnvironment.GetAddonDirectory(addonName)))
                {
                    DirectoryInfo di =
                        new DirectoryInfo(WowEnvironment.GetAddonDirectory(addonName));

                    if (FileSystem.IsWorkingCopy(di.FullName))
                    {
                        item.Group = _addonListView.Groups[statusSubItem.Text = "SVN"];
                    }
                    else
                    {
                        if (
                            WowEnvironment.SupportsPackOperation(
                                WowEnvironment.PackOperation.PACK, di.Name))
                        {
                            statusSubItem.Text = "Packages";
                            item.Group = _addonListView.Groups["Packages"];
                        }
                        else
                        {
                            string partOf = WowEnvironment.PartOfPackage(di.Name);
                            if (!string.IsNullOrEmpty(partOf))
                            {
                                statusSubItem.Text = "PackageContents";
                                item.Group = _addonListView.Groups["PackageContents"];
                            }
                            else
                            {
                                statusSubItem.Text = "Installed";
                                item.Group = _addonListView.Groups["Installed"];
                            }
                        }

                        if (bBuildVirtualLists)
                        {
                            _virtualInstalled.Add(item);
                        }

                        _addonMap.Add(addonName, item);
                    }
                }
                else
                {
                    rssAddonItem i = WowAceFilesServer.FilesLookup[addonName];
                    uint toc;
                    uint addontoc = i.@interface;

                    uint.TryParse(Settings.Default.LastTOCValue, out toc);


                    if (toc == 0 || toc == addontoc)
                    {
                        statusSubItem.Text = "Not Installed";
                        item.Group = _addonListView.Groups["NotInstalled"];
                    }
                    else
                    {
                        statusSubItem.Text = "Outdated";
                        item.Group = _addonListView.Groups["Outdated"];
                    }
                }
            }
            catch (Exception e)
            {
                _outputWriter.WriteLine("SetListViewGroup '" + addonName + "' : " +
                                        e.Message);
            }
        }

        private static void ShellOpenURL(string target)
        {
            try
            {
                Process.Start(target);
            }
            catch (Win32Exception e)
            {
                if (e.ErrorCode == -2147467259)
                {
                    MessageBox.Show(e.Message, Resources.ShellError);
                }
            }
            catch (Exception other)
            {
                MessageBox.Show(other.Message, Resources.ShellError);
            }
        }

        private void SortListViewItems()
        {
            // Update group sorting state
            if (_addonListView.ShowGroups)
            {
                //                 foreach (ListViewGroup Group in _addonListView.Groups)
                //                 {
                //                     ListViewItem[] Items = new ListViewItem[Group.Items.Count];
                //                     Group.Items.CopyTo(Items, 0);
                //                     Group.Items.Clear();
                //                     Array.Sort(Items, _listViewColumnSorter);
                //                     foreach (ListViewItem it in Items)
                //                     {
                //                         it.Group = null;
                //                     }
                //                     Group.Items.AddRange(Items);
                //                 }
            }
            else
            {
                _addonListView.Sort();
            }
        }

        private void ClearBuildCache()
        {
            _fullAddonList = null;
            _virtualInstalledTmp = null;
            _virtualUpdatedTmp = null;
        }

        private void PrepBuildCache()
        {
            if (_fullAddonList == null)
            {
                _fullAddonList = new ListViewItem[_addonListView.Items.Count];

                _addonListView.Items.CopyTo(_fullAddonList, 0);


                _virtualInstalledTmp = new List<string>(_virtualInstalled.Count);
                _virtualUpdatedTmp = new List<string>(_virtualUpdated.Count);
                foreach (ListViewItem item in _addonListView.Items)
                {
                    if (_virtualUpdated.Contains(item))
                    {
                        _virtualUpdatedTmp.Add(item.Name);
                    }
                    if (_virtualInstalled.Contains(item))
                    {
                        _virtualInstalledTmp.Add(item.Name);
                    }
                }
            }
        }

        private void RebuildVirtualLists(ref ListViewItem[] items)
        {
            _virtualUpdated.Clear();
            _virtualInstalled.Clear();
            _addonListView2.VirtualListSize = 0;
            _addonListView3.VirtualListSize = 0;

            foreach (ListViewItem item in items)
            {
                if (_virtualUpdatedTmp.Contains(item.Name))
                {
                    _virtualUpdated.Add(item);
                }
                if (_virtualInstalledTmp.Contains(item.Name))
                {
                    _virtualInstalled.Add(item);
                }
            }

            _addonListView2.VirtualListSize = _virtualUpdated.Count;
            _addonListView3.VirtualListSize = _virtualInstalled.Count;
        }


        private void RebuildList(ref ListViewItem[] items)
        {
            _lastSearchResult = items;
            _isInserting = true;
            _addonListView.SuspendLayout();

            // wipe out the addon list so we can replace the ones we want to keep 
            // amusingly, AddRange for things we want to keep is much faster than doing Removes for things we want to get rid of
            _addonListView.Items.Clear();


            _addonListView.BeginUpdate();

            if (items != null)
            {
                _addonListView.Items.AddRange(items);
            }


            for (int i = 0; i < _addonListView.Items.Count; i++)
            {
                ListViewItem cc = _addonListView.Items[i];
                SetListViewGroup(cc,
                                 cc.SubItems["Status"],
                                 cc.SubItems[INDEX_ITEMNAME].Text,
                                 false);
            }

            _itemCache.Clear();

            _addonListView.EndUpdate();

            SortListViewItems();


            _addonListView.ResumeLayout();

            _isInserting = false;
            UpdateCheckedItemStatusLabel();
        }

        private static void UninstallAddon(
            string addonName, TextWriter t, ICollection<string> list, Object oLock)
        {
            string localAddonFolder = WowEnvironment.GetAddonDirectory(addonName);

            if (!FileSystem.IsDirectoryProtected(localAddonFolder))
            {
                t.WriteLine(Resources.Deleting0, addonName);
                WowEnvironment.UninstallAddon(addonName, t, list, oLock);
            }
            else
            {
                t.WriteLine(Resources.SkippingProtectedMissing, addonName);
            }
        }

        private void UninstallItems(IEnumerable<string> items)
        {
            if (
                MessageBox.Show(Resources.AreYouSureYouWantToUninstall,
                                Resources.Confirm,
                                MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                EnableUserInteraction(false);
                _outputWriter.Clear();

                Application.DoEvents();
                Object o = new Object();
                foreach (string item in items)
                    UninstallAddon(item, _outputWriter, new List<string>(), o);

                _outputWriter.WriteLine(Resources.UninstallComplete);
                EnableUserInteraction(true);
            }

            ResetListViewGroups();
        }

        private void UpdateCheckedItemStatusLabel()
        {
            _addonCountStatusLabel.Text =
                String.Format(Resources.Marked01,
                              _addonListView.CheckedItems.Count,
                              _addonListView.Items.Count);
        }

        private void _addonListView_ColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e)
        {
            ListView l = sender as ListView;

            if (l != null)
            {
                ColumnHeader h = l.Columns[e.ColumnIndex];
                if (h != null &&
                    (h.Text == _versionHeader.Text || h.Text == _dateHeader.Text))
                {
                    int width = 6 + ((h.Index == 3) ? c3HW : c2HW);
                    //Size s = TextRenderer.MeasureText(h.Text, h.ListView.Font);

                    if (width > e.NewWidth)
                    {
                        Debug.WriteLine(string.Format("Canceled Width {0}->{1}, {2}",
                                                      h.Width, e.NewWidth, width));

                        e.Cancel = true;
                        h.Width = width;
                    }
                }
            }
        }

        private void _addonListView_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
        {
            ListView l = sender as ListView;
            if (l != null)
            {
                ColumnHeader h = l.Columns[e.ColumnIndex];

                if (h.Text != _status.Text && h.Text != _category.Text)
                {
                    Size s = TextRenderer.MeasureText(h.Text, h.ListView.Font);


                    if (h.Width < s.Width + 6)
                        h.Width = s.Width + 6;
                }
            }
        }

        private void forceCacheMissForUpdateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            WowAceFilesServer.ForceServerCacheMiss(
                new Uri("http://www.wowace.com/wau/WowAceUpdater.application"));
        }

        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            ShellOpenURL("http://www.wowace.com/wiki/WowAceUpdater");
        }

        private void webView_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            //webView.AllowNavigation = false;
        }

        private void toolStripMenuItem3_Click(object sender, EventArgs e)
        {
            ShellOpenURL(SOLUTIONS_THREAD);
        }

        private void toolStripMenuItem4_Click(object sender, EventArgs e)
        {
            Settings.Default.Reset();
            Settings.Default.Save();
            Close();}

        public delegate void AddWowInstallationFunction(string p);

        internal static void AddWowInstallation(string p)
        {
            WowAceUpdater.MainForm mf = ActiveForm as MainForm;

            if (mf == null)
                return;

            if (mf.InvokeRequired)
            {
                object[] o = {p};

                mf.BeginInvoke(new AddWowInstallationFunction(AddWowInstallation), o);
            }
            else
            {
                    ToolStripItemCollection items = mf.woWInstallsToolStripMenuItem.DropDownItems;

                    foreach (ToolStripMenuItem t in items)
                    { if (t.Text == p) return; }

                    ToolStripMenuItem tsmi = new ToolStripMenuItem(p);

                    items.Add(tsmi);

                    tsmi.Click += mf.tsmi_Click;
            }
        }

        void tsmi_Click(object sender, EventArgs e)
        {
            ToolStripMenuItem tsmi = sender as ToolStripMenuItem;

            if (tsmi == null) return;
            
            
            string text = tsmi.Text;
            if (Settings.Default.WowInstallDirectory != text)
            {
                Settings.Default.WowInstallDirectory = text;

                if (!Settings.Default.WowInstalls.Contains(text))
                    Settings.Default.WowInstalls.Add(text);

                Settings.Default.Save();

                RefreshList();
            }
        }

        #region Nested type: AddCategoryCallback

        private delegate void AddCategoryCallback(ToolStripComboBox c, string text);

        #endregion

        #region Nested type: BackgroundWorkerParams

        private class BackgroundWorkerParams
        {
            #region field

            public readonly ICollection<string> AddonNames;
            public readonly bool DeleteBeforeExtract;
            public readonly ExternalMode SkipExternals;
            public readonly bool SkipVersionCheck;

            #endregion

            #region Constructors

            public BackgroundWorkerParams(
                ICollection<string> addonNames,
                ExternalMode skipExternals,
                bool skipVersionCheck,
                bool DeleteBeforeExtract)
            {
                AddonNames = addonNames;
                SkipExternals = skipExternals;
                SkipVersionCheck = skipVersionCheck;
                this.DeleteBeforeExtract = DeleteBeforeExtract;
            }

            #endregion
        }

        #endregion

        #region Nested type: CheckForUpdatesFunction

        private delegate void CheckForUpdatesFunction();

        #endregion

        #region Nested type: DAndEArgs

        private class DAndEArgs
        {
            #region field

            internal readonly string addonName;
            internal readonly bool deleteBeforeExtract;
            internal readonly ICollection<string> list;
            internal readonly ICollection<string> listCurrent;
            internal readonly ICollection<string> listDone;
            internal readonly Object oLock;
            internal readonly ExternalMode skipExternals;
            internal readonly bool skipVersionCheck;

            internal TextWriter outputWriter;

            #endregion

            #region Constructors

            internal DAndEArgs(
                string addonName,
                ExternalMode skipExternals,
                bool skipVersionCheck,
                bool deleteBeforeExtract,
                ICollection<string> list,
                ICollection<string> listDone,
                ICollection<string> listCurrent,
                Object oLock)
            {
                this.addonName = addonName;
                this.skipExternals = skipExternals;
                this.skipVersionCheck = skipVersionCheck;
                this.deleteBeforeExtract = deleteBeforeExtract;
                this.list = list;
                this.listDone = listDone;
                this.listCurrent = listCurrent;
                this.oLock = oLock;
            }

            #endregion
        }

        #endregion

        #region Nested type: DoUpdateFunction

        private delegate void DoUpdateFunction();

        #endregion

        #region Nested type: ExternalMode

        private enum ExternalMode
        {
            WITH,
            WITHOUT,
            AUTO
        } ;

        #endregion

        #region Nested type: SVNProcess

        private class SVNProcess : Process
        {
            private string _addon;

            public string Addon
            {
                get { return _addon; }
                set { _addon = value; }
            }
        }

        #endregion

        #region Nested type: TOCVersionUpdatedFunction

        private delegate void TOCVersionUpdatedFunction();

        #endregion

        private void woWInstallsToolStripMenuItem_DropDownOpening(object sender, EventArgs e)
        {
            foreach (string s in Settings.Default.WowInstalls)
            {
                AddWowInstallation(s);
            }

            ToolStripItemCollection items = woWInstallsToolStripMenuItem.DropDownItems;

            foreach (ToolStripMenuItem t in items)
            {
                 t.Checked = (t.Text == Settings.Default.WowInstallDirectory) ? true : false; 
            }

        }

//GET /wau/WowAceUpdater.application HTTP/1.1
//Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/x-shockwave-flash, */*
//Accept-Language: en-us
//UA-CPU: x86
//Accept-Encoding: gzip, deflate
//Cache-Control: no-cache
//User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 1.1.4322)
//Proxy-Connection: Keep-Alive
//Host: www.wowace.com

        public static void VistaFail()
        {
            MessageBox.Show(
                "You are trying to update from a directory you dont have the necessary permissions. Do not run WoW from the Program Files directory unless you know how to adjust the permissions. Move the WoW folder to your desktop or another location and run the game from there",
                "System Configuration Incorrect.", MessageBoxButtons.OK, MessageBoxIcon.Error);
            
           
        }

        private void MainForm_Load(object sender, EventArgs e)
        {

        }

    }
}